2024 最新,钻石VIP学习


2024私活联盟整起!

如果你是有一定的开发经验,我相信你一定被项目 lib 下的 JAR 包折磨过,如果碰上兼容问题,更是逐个下载不同版本 JAR 包进行替换排查,相信是每个程序员都不想再经历一边的噩梦。

Maven 的出现则大大降低开发人员的准备工作,让开发人员更专心与业务,下面即介绍 Maven 基本使用。

Maven 是一个项目管理工具,可以对 Java 项目进行构建、依赖管理。

一、基础配置1. 仓库配置

在 Maven 中引入了仓库的概念,开发人员将所编写的 JAR 按照相应格式推送到仓库中,当其他开发者需要引用这个 jar 包时在工程中引用相应依赖,则会先从中央仓库进行下载到本地仓库,此时项目将读取本地仓库的内容。

对于部分组织或机构通常会在此基础上额外搭建私人仓库,在引用依赖时会先从私人仓库进行读取,如果未找到再从中央仓库下载至私人仓库,最后再下载到本地仓库。

导入javaweb项目报错_java导入_导入java.util

通过这种方式开发者则无需再手动管理繁杂的项目 JAR 包,从而实现更高的效率。

2. 基本信息

一个最基本的 Maven 项目通常应包含如下内容,当我们引用一个模块时,也是通过groupId、artifactId、version三项内容进行确定。

导入javaweb项目报错_java导入_导入java.util

下面是一个基本定义示例:


<project ...>
    
    <modelVersion>4.0.0</modelVersion>

    <groupId>xyz.ibudai</groupId>
    <artifactId>maven-demo</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <version>maven demo</version>
    <description>This is maven demo.</description>
    
</project>

二、依赖管理1. 依赖引入

通过dependencies标签我们即可导入所需要的工程依赖。

<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.27</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>

其中scope的可选值如下:

导入java.util_导入javaweb项目报错_java导入

2. 间接依赖

当项目需要引用到其它依赖时,只需指定所依赖的工程的基本信息即可,剩下的一切都交给 Maven 处理。即便是所要依赖的工程依赖了其它工程,我们也只需引入项目所直接的依赖的工程。

如下图示例中Dependency-A引用了Dependency-B,而Dependency-B又依赖于Dependency-C,在传统项目中若在Dependency-A中引用Dependency-B则需要同时手动添加Dependency-B与Dependency-C所对应的 JAR 包,但在 Maven 中我们只需要引入Dependency-B即可, Mavne 会自动将子模块所依赖的包导入。

导入javaweb项目报错_java导入_导入java.util

依赖顺序

在 maven 工程中遵循先定义先导入的原则,即当存在多个相同间接依赖,优先导入其父依赖定义在前的简洁依赖。

举个例子,如工程中引入Dependency-A与Dependency-B两个依赖,二者又分别引用了不同版本的Dependency-C,但对于 Maven 而言最终编译时同一个依赖即便是不同的版本也只会选择一份。

其计算规则如下:若Dependency-A定义在Dependency-B之前则最终将导入Dependency-A中的 C-1.0 版本。而在右侧图例中虽然Dependency-A引入优先级高于Dependency-B,但是 C-2.0 的间接依赖层级高于 C-1.0,因此将导入 C-2.0 版本。

导入javaweb项目报错_导入java.util_java导入

3. 依赖排除

在引用多个模块时可能会发生版本兼容冲突问题,通过excludes标签即可实现依赖排除。

如下我们在工程中引入了demo-a依赖,但其又引用dependency-b依赖,如想要在当前工程中移除dependency-b依赖,此时即可通过excludes标签将dependency-b排除依赖。

<dependencies>
    <dependency>
        <groupId>xyz.ibudai</groupId>
        <artifactId>demo-a</artifactId>
        <version>1.0.0</version>
        <excludes>
            <exclude>
                <groupId>xyz.ibudai</groupId>
                <artifactId>dependency-b</artifactId>
                <version>1.0.0</version>
            </exclude>
        </excludes>
    </dependency>
</dependencies>

除了手动通过excludes标签排除依赖,被引模块也可以在导入依赖时通过optional标签禁用依赖传递。

上述示例中若在demo-a工程中引入dependency-b依赖时添加optional标签,那么其它工程在引入demo-a依赖时将不会将 dependency-b作为间接依赖导入。

<dependencies>
    <dependency>
        <groupId>xyz.ibudai</groupId>
        <artifactId>demo-b</artifactId>
        <version>1.0.0</version>
        <optional>true</optional>
    </dependency>
</dependencies>

4. 变量配置

当项目中引入了大量依赖,为了方便管理通常将引入依赖的版本通过变量进行统一配置,从而实现更直观的依赖管理。

通过properties标签即可自定义变量配置,然后使用${}引用变量。

<properties>
    <mysql.version>8.0.30</mysql.version>
    <junit.version>4.13.2</junit.version>
</properties>

<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        
        <version>${mysql.version}</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
    </dependency>
</dependencies>

三、模块配置1. 模块管理

当我们项目包含多个子项目时,通过modules标签即可实现模块管理。


<modules>
    <module>module-1</module>
    <module>module-2</module>
</modules>

如下在maven-demo中又包含了module-1和module-2两个工程。

导入javaweb项目报错_java导入_导入java.util

2. 模块继承

通过parent即可标记当前模块的父模块,且子模块将会继承父模块中的所有依赖配置。子模块若没有指定的groupId和version默认继承父模块中的配置。

其中relativePath用于指定父模块的 POM 文件目录,省略时默认值为../pom.xml即当前目录的上一级中,若仍未找到则会在本地仓库中寻找。


<parent>
    <groupId>xyz.ibudai</groupId>
    <artifactId>maven-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <relativePath>../pom.xml</relativePath>
</parent>

<artifactId>module-1</artifactId>

四、统一管理1. 依赖管理

当一共项目包含多个模块,且多个模块引用了相同依赖时显然重复引用是不太合适的,而通过dependencyManagement即可很好的解决依赖共用的问题。

将项目依赖统一定义在父模块的dependencyManagement标签中,子模块只需继承父模块并在dependencies引入所需的依赖,便可自动读取父模块dependencyManagement所指定的版本。

dependencyManagement既不会在当前模块引入依赖,也不会给其子模块引入依赖,但其可以被继承的,只有在子模块下同样声明了该依赖,才会引入到模块中,子模块中只需在依赖中引入groupId与artifactId即可, 也可以指定版本则会进行覆盖。

2. 模块示例

接下来以下图中的模块层级关系进行举例:

导入javaweb项目报错_java导入_导入java.util

maven-demo

在maven-demo的dependencyManagement定义mysql和junit两个依赖。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
        </dependency>
    </dependencies>
</dependencyManagement>

module-1

在module-1中继承maven-demo工程,引入 mysql,无需指定版本,将会自动读取父模块中dependencyManagement中所指定的版本。当然你也可以选择指定版本,则将会进行覆盖,但并不建议这么操作,将提高项目维护难度。

module-1的 pom 文件内容如下:

<parent>
    <groupId>xyz.ibudai</groupId>
    <artifactId>maven-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
</parent>

<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

module-2

在module-2配置同module-1,通过dependencyManagement我们即实现了项目依赖版本的统一管理。

<parent>
    <groupId>xyz.ibudai</groupId>
    <artifactId>maven-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
</parent>

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
</dependencies>

3. 依赖导入

上面介绍了如何通过dependencyManagement实现全局的依赖版本管理,但如果工程中的两个子模块都需要配置相同的dependencyManagement配置时,当然你可以选择通过继承父模块来实现,也可以用笨办法直接复制粘贴一份。

在上述的maven-demo创建同级模块maven-demo1,如果要实现maven-demo中配置的dependencyManagement则在其dependencyManagement配置中导入maven-demo并将scope设置为import,并将type设置为pom。

通过导入即可实现更轻量化的模块信息继承,具体配置内容如下:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>xyz.ibudai</groupId>
            <artifactId>maven-demo</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            
            
            <scope>import</scope>
            
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>

五、插件管理

经过前面的介绍相信对于 Maven 你已经有了一个初步的了解,但 Maven 除了依赖管理之外提供一系列强大的插件,插件对于 Maven 而言可谓时左膀右臂但却经常被人忽略。

今天就让我介绍一下 Maven 中常用的构建插件。

1. Jar

在使用 Java 开发时通常情况下我们都会将工程打包为 JAR 文件,首先了解一下 JAR 的文件结构。

下图即为通过 Maven 打包后的 JAR 文件,其中org.example目录为工程中定义的包名,存在编译后的.class文件,META-INF目录用于存放工程的元数据信息。

java导入_导入java.util_导入javaweb项目报错

如上图中META-INF下的MANIFEST.MF文件内容如下:

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: great
Created-By: Apache Maven 3.6.3
Build-Jdk: 1.8.0_202

而通过maven-jar-plugin插件我们即可在添加额外信息至打包后的 JAR 文件,插件配置信息如下:

<plugin>  
    <groupId>org.apache.maven.plugins</groupId>  
    <artifactId>maven-jar-plugin</artifactId>  
    <version>2.3.1</version>  
    <configuration>  
        <archive>  
            <manifest>  
    <mainClass>org.example.MyTest</mainClass> 
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
    <addDefaultImplementationEntries>true</addDefaultImplementationEntries> 
            </manifest>
            
            <manifestEntries>  
                <Plugin-Id>demo-plugin</Plugin-Id>  
                <Plugin-Version>1.0.0</Plugin-Version>  
            </manifestEntries>  
        </archive>  
    </configuration>  
</plugin>

在之前的工程 POM 文件中添加上述构建插件重新进行打包,可以看到MANIFEST.MF文件中即添加了我们配置的额外属性。

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: great
Build-Jdk: 1.8.0_202
# Specification entries
Specification-Title: maven-v1
Specification-Version: 1.0-SNAPSHOT
# Implementation entries
Implementation-Title: maven-v1
Implementation-Version: 1.0-SNAPSHOT
Implementation-Vendor-Id: org.example
# Manifest
Main-Class: org.example.MyTest
# ManifestEntries
Plugin-Id: demo-plugin
Plugin-Version: 1.0.0

2. Assembly

在普通 Maven 工程打包时默认仅会编译工程中新建的 java 文件并存储其.class文件,对于POM文件中引用的第三方依赖并不会一同打包。

如新建一个 Maven 工程并在依赖中导入Jackson依赖库并进行打包编译,可以看到下图编译后的 JAR 文件中只有工程中新建的MyTest.class文件,项目中所导入的依赖并没有被一起打包。

导入javaweb项目报错_导入java.util_java导入

而通过assembly插件即可将 POM 配置中的所有依赖一同打包编译至 JAR 文件中。

其中execution标签定义了assembly插件的作用阶段,如这里设置了在Maven package即打包阶段生效。

<plugin>  
    <groupId>org.apache.maven.plugins</groupId>  
    <artifactId>maven-assembly-plugin</artifactId>  
    <version>3.1.0</version>  
    <configuration>  
        <descriptorRefs>  
            <descriptorRef>jar-with-dependencies</descriptorRef>  
        </descriptorRefs>  
        
        <finalName>${project.artifactId}-${project.version}-all</finalName>  
        <appendAssemblyId>false</appendAssemblyId>  
        <attach>false</attach>  
        <archive>  
            <manifest>  
    <mainClass>fully.qualified.MainClass</mainClass> 
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
    <addDefaultImplementationEntries>true</addDefaultImplementationEntries> 
            </manifest>   
        </archive>  
    </configuration>  
    <executions>  
        <execution>  
         
            <id>make-assembly</id>  
            <phase>package</phase>  
            <goals>  
                <goal>single</goal>  
            </goals>  
        </execution>  
    </executions>  
</plugin>

在工程 POM 配置中添加上述信息并重新编译打包工程,可以看到此时 JAR 文件中除了自定义创建的MyTest.clss文件外同时包含了依赖的第三方库。

导入java.util_java导入_导入javaweb项目报错

3. Shade

Shade 插件的功能更为强大,其提供了两个功能:第一个即与assembly类似可实现依赖的打包编译,与assembly不同的是 Shade 提供了更灵活的执行策略,可指定需要打包编译的依赖集合。

另一个即实现包的重命名功能,我们都知道 Maven 并不允许在一共工程中同时引入单个依赖的不同版本,而通过 Shade 插件即可实现二次包装从而绕开该限制。

下面介绍一个 Shade 插件中各标签的使用。

artifactSet

通过includes标签可以指定需要一同打包编译的第三方依赖。

定义的格式为:groupId:artifactId。

<artifactSet>  
    <includes>  
        <include>groupId:artifactId</include>  
    </includes>  
</artifactSet>  

relocations

通过relocations标签即可实现模块的重命名功能。

其中pattern为需要重命名的模块包,shadedPattern为重命名后的模块名。

<relocations>  
    <relocation>  
        <pattern>old.package.name</pattern>  
        <shadedPattern>new.package.name</shadedPattern>  
    </relocation>
</relocations>  

filters

通过filters标签可以实现非必要文件的排除,如常见的协议文件等,可通过文件名或类型实现匹配。

<filters>  
    <filter>  
        <artifact>*:*</artifact>  
        <excludes>  
            <exclude>filename</exclude>  
            <exclude>file pattern</exclude>  
        </excludes>  
    </filter>  
</filters>  

完整配置

Shade 同样可以通过execution设置作用阶段,上述介绍标签的完整配置内容如下:

<plugins>  
    <plugin>  
        <groupId>org.apache.maven.plugins</groupId>  
        <artifactId>maven-shade-plugin</artifactId>  
        <version>3.2.0</version>  
        <executions>  
              
            <execution>  
                <phase>package</phase>  
                <goals>  
                    <goal>shade</goal>  
                </goals>  
            </execution>  
        </executions>  
        <configuration>  
            <minimizeJar>true</minimizeJar>  
              
            <artifactSet>  
                <includes>  
                    <include>com.fasterxml.jackson.core:jackson-core</include>  
                </includes>  
            </artifactSet>  
              
            <relocations>  
                <relocation>  
                      
                    <pattern>com.fasterxml.jackson.core</pattern>  
                      
                    <shadedPattern>com.ibudai.fasterxml.jackson.core</shadedPattern>  
                </relocation>   
            </relocations>  
              
            <filters>  
                <filter>  
                    <artifact>*:*</artifact>  
                    <excludes>  
                        <exclude>META-INF/license/**</exclude>  
                        <exclude>META-INF/*</exclude>  
                        <exclude>LICENSE</exclude>  
                        <exclude>NOTICE</exclude>  
                    </excludes>  
                </filter>  
            </filters>  
        </configuration>  
    </plugin>  
</plugins>

在之前的工程中添加上述配置并重新打包,可以看到编译后的 Jackson 模块包层级已经变成我们自定义的内容,而 Java 的类加载即通过类的完成限定名(包名+类名)来区分是否为同一个类,因此通过 Shade 插件即可实现 Maven 的单一工程多版本引入。

六、构建配置

在上面介绍了工程的依赖管理与多模块的管理配置,下面介绍一下工程打包构建时涉及的配置。

注意以下所有配置项都是定义在标签组内,下述不再重复说明。

1. 版本指定

标签内可指定工程打包编译时使用的 JDK 版本,可根据服务器环境手动修改版本。

<plugins>
    <plugin>
        
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
            <source>8</source>
            <target>8</target>
        </configuration>
    </plugin>
</plugins>

2. 文件排除

默认项目打包后/resources目录下文件都将统一打包进编译后的 JAR 文件,但为了方便配置修改通常将配置文件排除打包,使用时只需将文件放置于 JAR 同级即可。

如下示例中将application.yml文件排除打包,后续若需要修改配置无需重新打包只需重启项目即可。

<resources>
    <resource>
        
        <directory>src/main/resources</directory>
        <excludes>
            <exclude>application.yml</exclude>
        </excludes>
    </resource>
</resources>

3. 主类配置

在打包时可能出现无法识别工程主类的问题,导致编译后的文件无法正常运行,此时则可以在 pom 文件中手动设置工程的主类。

其中中配置的为项目主类的完成限定名。

<plugins>
    <plugin>
        
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
            <mainClass>xyz.ibudai.TestWebApplication</mainClass>
            <layout>JAR</layout>
        </configuration>
    </plugin>
</plugins>

来源:/post/726629321705416300

·················END·················

你好,我是小孟,10年开发老司机,小作坊boss、做过码农、主管、产品经理。喜欢自由,讨厌职场的勾心斗角。我的偶像是乔布斯,10年前选择计算机这个行业,就是因为热爱。现在已而立之年,虽然没有当初追寻技术的单纯,但依然热爱。技术改变世界,知识改变命运是我不变的信念。学习、思考、因时代变化而变化是我的武器。如果我觉得一件事,值得干,至少我会坚持5年。在我毕业一年后,我就搞定了房贷、车贷等一切贷款,所以我可以自由。我不喜欢循规蹈矩和被安排的生活,大学时候就喜欢折腾,现在也是。我相信坚持的力量,如果能把一件事坚持下去,真的可以打败99%的人。关注我,一起聊技术、职场、人生和好玩的事。

你对的起时间,时间也会对的你。一个人可以走的很快,一群人走的很远。开发项目,

限时特惠:本站每日持续更新海内外内部创业教程,一年会员只需88元,全站资源免费下载点击查看详情
站长微信:nnxmw123