Java 集成 maven-invoker 编译 Maven 项目

背景

在之前的文章 Java 集成Maven Embedder 编译 Maven 项目 中介绍了如何通过嵌入的maven来编译maven项目,但是这玩意儿在使用过程中发现如果有多个jdk环境变量,就会导致编译出问题,因此,换个路子,使用 maven-invoker来编译maven项目,相比之下,此种方式需要:

  • 安装jdk(一般java服务都会安装jdk,也有些比较蛋疼的会安装jre)
  • 安装maven

如果使用到了内部maven仓库,最好在服务部署的时候,内置一个settings.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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<?xml version="1.0" encoding="UTF-8"?>

<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
<!-- 本地仓库地址,使用前记得修改为自己的实际使用路径 -->
<localRepository>D:\DataCache\maven</localRepository>
<mirrors>
<!-- 阿里镜像 -->
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>

<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>

<mirror>
<id>central</id>
<name>Maven Repository Switchboard</name>
<url>http://repo1.maven.org/maven2/</url>
<mirrorOf>central</mirrorOf>
</mirror>

<mirror>
<id>repo2</id>
<mirrorOf>central</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://repo2.maven.org/maven2/</url>
</mirror>

<mirror>
<id>ibiblio</id>
<mirrorOf>central</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://mirrors.ibiblio.org/pub/mirrors/maven2/</url>
</mirror>

<mirror>
<id>jboss-public-repository-group</id>
<mirrorOf>central</mirrorOf>
<name>JBoss Public Repository Group</name>
<url>http://repository.jboss.org/nexus/content/groups/public</url>
</mirror>

<mirror>
<id>google-maven-central</id>
<name>Google Maven Central</name>
<url>https://maven-central.storage.googleapis.com
</url>
<mirrorOf>central</mirrorOf>
</mirror>

<!-- 中央仓库在中国的镜像 -->
<mirror>
<id>maven.net.cn</id>
<name>oneof the central mirrors in china</name>
<url>http://maven.net.cn/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
</settings>

使用maven-invoker编译

pom.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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.wick.maven</groupId>
<artifactId>maven-test</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>maven-test</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-invoker</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.11</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

MavenCompiler

1
2
3
public interface MavenCompiler {
void compile(MavenCompileRequest request);
}

MavenCompileRequest

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
40
package org.wick.maven.dto;

import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.List;

/**
* 编译参数
*/

@Getter
@Setter
@ToString
@Builder
public class MavenCompileRequest {

/**
* jdk 安装目录
*/
private String javaHome;

/**
* maven安装目录
*/
private String mavenHome;

/**
* maven goals
*/
private List<String> goals;

/**
* 代码路径
*/
private String codePath;
}

MavenCompilerImpl

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
package org.wick.maven.manager.impl;

import lombok.extern.slf4j.Slf4j;
import org.apache.maven.shared.invoker.*;
import org.wick.maven.dto.MavenCompileRequest;
import org.wick.maven.manager.MavenCompiler;

import java.io.File;

@Slf4j
public class MavenCompilerImpl implements MavenCompiler {

@Override
public void compile(MavenCompileRequest request) {
log.info("Compiling Maven project, request: {}", request);
InvocationRequest invocationRequest = new DefaultInvocationRequest();
invocationRequest.setGoals(request.getGoals());
invocationRequest.setMavenHome(new File(request.getMavenHome()));
invocationRequest.setJavaHome(new File(request.getJavaHome()));
invocationRequest.setOutputHandler(log::info);
invocationRequest.setErrorHandler(log::error);
invocationRequest.setPomFile(new File(request.getCodePath()));
try {
Invoker invoker = new DefaultInvoker();
InvocationResult result = invoker.execute(invocationRequest);
if (result.getExitCode() != 0) {
throw new RuntimeException("Maven build failed with exit code: " + result.getExitCode());
}
} catch (MavenInvocationException e) {
throw new RuntimeException("Maven invocation failed", e);
}
}
}

康康效果

测试代码

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
MavenCompileRequest request = MavenCompileRequest.builder()
.javaHome("C:\\Program Files\\Java\\jdk-11")
.codePath("D:\\workspace\\onetest-code-coverage")
.mavenHome("D:\\SoftWare\\apache-maven-3.9.9")
.goals(MavenGoal.COMMAND).build();
MavenCompiler mavenCompiler = new MavenCompilerImpl();
mavenCompiler.compile(request);
}

输出

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
22:09:50.217 [main] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- Compiling Maven project, request: MavenCompileRequest(javaHome=C:\Program Files\Java\jdk-11, mavenHome=D:\SoftWare\apache-maven-3.9.9, goals=[clean, compile, -Dmaven.test.skip=true, --batch-mode, -T 20 ], codePath=D:\workspace\onetest-code-coverage)
[WARN] Maven will be executed in interactive mode, but no input stream has been configured for this MavenInvoker instance.
22:09:51.375 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] Scanning for projects...
22:09:51.716 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] Downloading from aliyun-repos: https://maven.aliyun.com/repository/public/io/rsocket/rsocket-bom/1.1.3/rsocket-bom-1.1.3.pom
22:09:52.227 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] Downloaded from aliyun-repos: https://maven.aliyun.com/repository/public/io/rsocket/rsocket-bom/1.1.3/rsocket-bom-1.1.3.pom (2.6 kB at 5.2 kB/s)
22:09:52.248 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [WARNING]
22:09:52.248 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [WARNING] Some problems were encountered while building the effective model for com.wick:onetest-code-coverage:jar:0.0.1
22:09:52.248 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [WARNING] 'dependencies.dependency.systemPath' for com.org:jacoco-cli:jar should not point at files within the project directory, ${project.basedir}/src/main/resources/lib/org.jacoco.cli-0.8.7-nodeps.jar will be unresolvable by dependent projects @ line 130, column 25
22:09:52.248 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [WARNING]
22:09:52.248 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
22:09:52.248 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [WARNING]
22:09:52.248 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
22:09:52.248 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [WARNING]
22:09:52.256 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO]
22:09:52.256 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] Using the MultiThreadedBuilder implementation with a thread count of 20
22:09:52.261 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO]
22:09:52.261 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] -------------------< com.wick:onetest-code-coverage >-------------------
22:09:52.261 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] Building onetest-code-coverage 0.0.1
22:09:52.261 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] from pom.xml
22:09:52.261 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] --------------------------------[ jar ]---------------------------------
22:09:52.782 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO]
22:09:52.782 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] --- clean:3.2.0:clean (default-clean) @ onetest-code-coverage ---
22:09:52.847 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] Deleting D:\workspace\onetest-code-coverage\target
22:09:52.868 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO]
22:09:52.868 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] --- resources:3.2.0:resources (default-resources) @ onetest-code-coverage ---
22:09:52.992 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] Using 'UTF-8' encoding to copy filtered resources.
22:09:52.992 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] Using 'UTF-8' encoding to copy filtered properties files.
22:09:52.997 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] Copying 3 resources
22:09:53.011 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] Copying 10 resources
22:09:53.027 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO]
22:09:53.027 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] --- compiler:3.10.1:compile (default-compile) @ onetest-code-coverage ---
22:09:53.106 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] Changes detected - recompiling the module!
22:09:53.109 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] Compiling 72 source files to D:\workspace\onetest-code-coverage\target\classes
22:09:55.061 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] ------------------------------------------------------------------------
22:09:55.061 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] BUILD SUCCESS
22:09:55.061 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] ------------------------------------------------------------------------
22:09:55.064 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] Total time: 3.701 s (Wall Clock)
22:09:55.064 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] Finished at: 2025-03-09T22:09:55+08:00
22:09:55.064 [StreamPumper-systemOut] INFO org.wick.maven.manager.impl.MavenCompilerImpl -- [INFO] ------------------------------------------------------------------------

总结

以上,就是通过 maven-invoker 来实现maven项目编译的过程,代码其实比较简单,但是运行起来比maven-embedder可靠一点,尤其是需要编译不同jdk版本的项目时,此种方式格外可靠。最后,附上 MavenGoal.COMMAND的代码

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
40
41
42
43
44
45
package org.wick.maven.dto;

import java.util.ArrayList;
import java.util.List;

public class MavenGoal {
/**
* 清理构建产物
*/
public static final String CLEAN = "clean";

/**
* 编译 class 文件
*/
public static final String COMPILE = "compile";

/**
* 打包
*/
public static final String PACKAGE = "package";

/**
* 跳过测试
*/
public static final String SKIP_TEST = "-Dmaven.test.skip=true";

/**
* 批处理模式
*/
public static final String BATCH_MODE = "--batch-mode";

/**
* 多核编译
*/
public static final String PARALLEL = "-T " + Runtime.getRuntime().availableProcessors() + " ";

public static final List<String> COMMAND = new ArrayList<>() {{
add(CLEAN);
add(COMPILE);
add(SKIP_TEST);
add(BATCH_MODE);
add(PARALLEL);
}};
}

对了,那一长串日志确实是我用来凑字数的~~~