Maven 开发随笔

Maven 常规配置

Maven 调试技巧

  • mvn dependency:tree,打印依赖树
  • mvn clean -X,使用 -X 参数输出详细的日志信息
  • mvn -X,查看当前生效的是哪个 settings.xml 配置文件
  • mvn help:effective-settings,查看正在起作用的是那个 settings.xml 的文件内容

Maven 打包跳过测试用例

  • 使用命令 mvn install -DskipTests,不执行测试用例,但会编译测试用例类的代码
  • 使用命令 mvn install -Dmaven.test.skip=true,不但跳过单元测试的运行,也跳过单元测试代码的编译
  • 使用 Maven 插件的配置如下:
1
2
3
4
5
6
7
8
9
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<skipTests>true</skipTests>
<!-- <skip>true</skip> -->
</configuration>
</plugin>

Maven 指定编译的 JDK 版本

方式一

1
2
3
4
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

方法二

1
2
3
4
5
6
7
8
9
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>

方法三

该方式并非 Maven 官方配置,要使该方式能够生效首先必须满足以下两个条件:

  • 项目为一个 SpringBoot 工程
  • 项目的 POM 继承了 spring-boot-starter-parent
1
2
3
4
5
6
7
8
9
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>

<properties>
<java.version>1.8</java.version>
</properties>

Maven 测试时拷贝资源文件

@SpringBootTest 注解,只会加载 src/test 路径下的资源文件(如 XML 配置),并不会加载 src/main 路径下的资源文件。若需要在执行单元测试时,加载 src/main 路径下的资源文件,需要让 Maven 拷贝对应的资源文件到 src/test 路径下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
<!--单元测试时引用src/main/resources下的资源文件-->
<testResources>
<testResource>
<directory>src/main/resources</directory>
</testResource>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
</build>

Maven 生成项目源码的 Jar 包

有时候开发一个公共 Jar 包给别人引用,当别人打开包中的类的时候,默认情况下打开的是 IDE 工具反编译出来的 .class 文件,类中的注释什么的都看不到,此时 IDE 工具会提示可以 Download Sources,但是如果打包的时候没有同时打一个以 -sources.jar 结尾的源码 Jar 包,那么调用方下载源码包的时候就会失败。maven-source 插件就是用来打包源码的,可以部署到私有仓库上的,对于需要查看源码、注释和调试代码,有很大的帮助。

1
2
3
4
5
6
7
8
9
10
11
12
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>

Maven 将项目中的测试代码打包进 Jar 包

Maven 支持打包的插件列表如下:

pluginfunction
maven-jar-pluginmaven 默认打包插件,用来创建 project jar
maven-shade-plugin 用来打可执行包,executable (fat) jar
maven-assembly-plugin 支持定制化打包方式,例如 apache 项目的打包方式

添加 maven-assembly-plugin 插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>src/main/resources/assembly.xml</descriptors>
</configuration>
</execution>
</executions>
</plugin>

还可以在上面的 configuration 节点中指定执行 Jar 包时的 Test 主类:

1
2
3
4
5
6
7
8
<configuration>
<descriptors>src/main/resources/assembly.xml</descriptors>
<archive>
<manifest>
<mainClass>com.sample.TestMain</mainClass>
</manifest>
</archive>
</configuration>

创建 assembly.xml 配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">

<id>assembly</id>

<formats>
<format>jar</format>
</formats>

<includeBaseDirectory>false</includeBaseDirectory>

<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<unpack>true</unpack>
<scope>test</scope>
</dependencySet>
</dependencySets>

<fileSets>
<fileSet>
<directory>${project.build.directory}/test-classes</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>**/*.class</include>
</includes>
<useDefaultExcludes>true</useDefaultExcludes>
</fileSet>
</fileSets>
</assembly>

特别注意:上面 assembly.xml 里的配置,默认会将所有 Jar 包的源码一起打包(包括依赖的第三方 Jar 包),如果只希望打包项目自身的源码,那么则需要添加 exclude 节点来排除依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">

<id>assembly</id>

<formats>
<format>jar</format>
</formats>

<includeBaseDirectory>false</includeBaseDirectory>

<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<unpack>true</unpack>
<scope>test</scope>
<excludes>
<exclude>org.slf4j:slf4j-api</exclude>
<exclude>com.fasterxml.jackson.core:*</exclude>
<exclude>org.apache.httpcomponents:*</exclude>
<exclude>com.google.guava:guava</exclude>
</excludes>
</dependencySet>
</dependencySets>

<fileSets>
<fileSet>
<directory>${project.build.directory}/test-classes</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>**/*.class</include>
</includes>
<useDefaultExcludes>true</useDefaultExcludes>
</fileSet>
</fileSets>
</assembly>

运行以下打包命令,会生成 xxxx-1.0.0-SNAPSHOT-assembly.jar 文件,其中文件名里的 assembly 是由 assembly.xml 配置文件里的 id 节点指定:

1
$ mvn package

Maven 私有仓库配置

通过插件上传 Jar 包到私有仓库

编辑 Maven 的 settings.xml 配置文件,通过添加 server 节点来配置私有仓库的账号和密码,这里的 id 可以随便取名字,但必须与下面配置的 id 一致:

1
2
3
4
5
6
7
8
9
10
11
<server>
<id>nexus-releases</id>
<username>admin</username>
<password>admin123</password>
</server>

<server>
<id>nexus-snapshots</id>
<username>admin</username>
<password>admin123</password>
</server>

编辑 Maven 的 settings.xml 配置文件,通过添加 mirror 节点来配置私有仓库的地址,这里的 id 必须和上面 server 节点的 id 一致:

1
2
3
4
5
6
7
8
9
10
11
12
13
<mirror>
<id>nexus-releases</id>
<mirrorOf>*</mirrorOf>
<name>nexus maven releases repo</name>
<url>http://127.0.0.1:8081/nexus/content/repositories/releases/</url>
</mirror>

<mirror>
<id>nexus-snapshots</id>
<mirrorOf>*</mirrorOf>
<name>nexus maven snapshots repo</name>
<url>http://127.0.0.1:8081/nexus/content/repositories/snapshots/</url>
</mirror>

编辑项目的 pom.xml 文件,添加以下内容,这里的 id 必须与 上面 mirror 节点里的 id 一致:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<distributionManagement>
<repository>
<id>nexus-snapshots</id>
<name>Nexus Snapshots Repository</name>
<url>http://127.0.0.1:8081/nexus/content/repositories/snapshots/</url>
</repository>
<!--
<repository>
<id>nexus-releases</id>
<name>Nexus Releases Repository</name>
<url>http://127.0.0.1:8081/nexus/content/repositories/releases/</url>
</repository>
-->
</distributionManagement>

执行发布命令:

1
$ maven clean deploy

Maven 常见问题解决

上传 Jar 包到私有仓库出现 400 错误码

一般有 3 个导致出现上面问题的原因:

  • 一、pom.xml 中仓库 id 配置不对,检查 pom.xml 中配置的 distributionManagement 中的仓库 id、url 和私服 Nexus 中的是否相同
1
2
3
4
5
6
7
<distributionManagement>
<repository>
<id>nexus-snapshots</id>
<name>Nexus Snapshots Repository</name>
<url>http://127.0.0.1:8081/nexus/content/repositories/snapshots/</url>
</repository>
</distributionManagement>
  • 二、私服 Nexus 已经存在相同版本且代码完全一样的 Jar 包,同时部署策略为不允许覆盖;此时只需要将仓库对应的 Deployment Policy 设置为 Allow Redeploy 即可

maven-nexus-redeploy

  • 三、如果 Repository Policy 为 Release,则部署 Jar 包的版本号中不允许出现 snapshot 关键字;特别注意,Repository Policy 有两个选项,一个发布版本,一个是快照版本,要和部署 Jar 包的版本号完全对应

maven-nexus-repository-policy

上传 Jar 包到私有仓库出现 401 错误码

一般报 401 这个错误码,是因为没有发布权限,而没发布权限的原因,大部分都是因为密码错了导致,或者账号本身就没有发布 Jar 包的权限。如果是密码错误,则可以编辑 Maven 的 settings.xml 配置文件,通过添加 server 节点来配置私有仓库的账号和密码:

1
2
3
4
5
6
7
8
9
10
11
<server>
<id>nexus-releases</id>
<username>admin</username>
<password>admin123</password>
</server>

<server>
<id>nexus-snapshots</id>
<username>admin</username>
<password>admin123</password>
</server>

如果密码正确,账号本身也具有发布 Jar 包的权限,但依然提示 401 错误,那么此时应该检查当前生效的 settings.xml 配置文件是哪个,查询命令如下:

1
2
3
4
5
$ mvn -X
[DEBUG] Reading global settings from /usr/develop/maven-3.6.0/conf/settings.xml
[DEBUG] Reading user settings from /root/.m2/settings.xml
[DEBUG] Reading global toolchains from /usr/develop/maven-3.6.0/conf/toolchains.xml
[DEBUG] Reading user toolchains from /root/.m2/toolchains.xml

如果上面输出的 global settings 指向的配置文件不是所期望的,此时就应该注意了,可以使用以下命令进一步查看正在起作用的那个 settings.xml 的内容:

1
$ mvn help:effective-settings

Nexus 常见问题解决

指定 Nexus 使用的 JDK 版本

Nexus VersionSupported Sun/Oracle JRE version
1.9 and earlier5 or 6
2.0-2.56 or 7
2.6.x7u45+, only 8+ will not work
2.7.x-2.9.x7u45+, 8+ may work but is not thoroughly tested
2.10.x-2.11.17u45+, 8u25+
2.11.2+8u31+ strongly recommended, 7u79+ no further public updates as of April 2015
2.12.0-018u31+ strongly recommended, 11.0.9 not work

由于以前安装的 Nexus 版本为 2.12.0-01,JDK 版本为 8,后来 JDK 升级为 11 后,Nexus 无法启动,因此只能指定 Nexus 默认使用 JDK 8,方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 进入配置文件所在的目录
$ cd nexus/nexus-2.12.0-01/bin/jsw/conf

# 备份配置文件
$ cp wrapper.conf wrapper.conf.default

# 编辑配置文件,指定JDK的安装路径
$ vim wrapper.conf
wrapper.java.command=/usr/java/jdk1.8.0_102/bin/java

# 重启Nexus服务
$ service nexus restart

# 查看Nexus服务的运行状态
$ service nexus status