1. 问题
新版本的Jenkins
中的Maven
插件对JDK
版本的要求提高了,如下:
- Jenkins >= 1.520 requires Java 6 thus Maven jobs must be launched with Java >= 6.
- Jenkins >= 1.612 requires Java 7 thus Maven jobs must be launched with Java >= 7.
- Jenkins >= 2.54 requires Java 8 thus Maven jobs must be launched with Java >= 8.
- Jenkins >= 2.357 requires Java 11 thus Maven jobs must be launched with Java >= 11.
但是有些项目必须要求JDK 1.8
编译才能够成功(例如有些第三方依赖库只支持JDK8
)。正常情况下在命令行下使用Maven
编译可以通过export JAVA_HOME
的方式来解决。但是在Jenkins Maven Plugin
中没有办法指定JDK
版本。如果强制指定在Jenkins
任务中(Maven
类型项目)指定JDK8
,则编译的时候会报如下信息,然后强制选择新版本的JDK
:
1 [release-pas-admin] $ /usr/local/jdk1.8.0/bin/java -cp /var/jenkins_home/plugins/maven-plugin/WEB-INF/lib/maven35-agent-1.14.jar:/usr/local/maven/boot/plexus-classworlds-2.7.0.jar:/usr/local/maven/conf/logging jenkins.maven3.agent.Maven35Main /usr/local/maven /var/jenkins_home/war/WEB-INF/lib/remoting-3206.vb_15dcf73f6a_9.jar /var/jenkins_home/plugins/maven-plugin/WEB-INF/lib/maven35-interceptor-1.14.jar /var/jenkins_home/plugins/maven-plugin/WEB-INF/lib/maven3-interceptor-commons-1.14.jar 39495
2Exception in thread "main" java.lang.UnsupportedClassVersionError: hudson/remoting/Launcher has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0
3 at java.lang.ClassLoader.defineClass1(Native Method)
4 at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
5 at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
6 at java.net.URLClassLoader.defineClass(URLClassLoader.java:473)
7 at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
8 at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
9 at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
10 at java.security.AccessController.doPrivileged(Native Method)
11 at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
12 at org.codehaus.plexus.classworlds.realm.ClassRealm.findClassInternal(ClassRealm.java:313)
13 at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClassFromSelf(ClassRealm.java:432)
14 at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:42)
15 at org.codehaus.plexus.classworlds.realm.ClassRealm.unsynchronizedLoadClass(ClassRealm.java:271)
16 at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:247)
17 at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:239)
18 at jenkins.maven3.agent.Maven35Main.main(Maven35Main.java:136)
19 at jenkins.maven3.agent.Maven35Main.main(Maven35Main.java:66)
20ERROR: ================================================================================
21ERROR: Invalid project setup: Connection reset
22ERROR: [JENKINS-18403][JENKINS-28294] JDK 'jdk1.8.0' not supported to run Maven projects.
23ERROR: Maven projects have to be launched with a Java version greater or equal to the minimum version required by the controller.
24ERROR: Use the Maven JDK Toolchains (plugin) to build your maven project with an older JDK.
25ERROR: Retrying with agent Java and setting compile/test properties to point to /usr/local/jdk1.8.0.
26ERROR: ================================================================================
2. ToolChain
Maven
本身有个机制,可以用来解决以上问题。这个机制就是toolchain
。
A Toolchain is a preconfigured object that Maven plugins can use for tool configuration retrieval (location and other information).
The toolchains-plugin can read available toolchains on the user’s computer and match them against the toolchain requirements of the project (as configured in pom.xml): if match is found, the toolchain instance is made available to other Maven plugins.
With jdk toolchain, for example, instead of being stuck with the JDK used to run Maven, all plugins can use the same other JDK instance without hardcoding absolute paths into the pom.xml and without configuring every plugin that require path to JDK tools.
通过在~/.m2/toolchains.xml
定义JDK
,然后通过maven-toolschains-plugin
在项目中指定对应标识的JDK
,就可以在编译的时候做到使用与运行Maven不同版本的JDK编译项目这个目的。
2.1 toolchains.xml
首先在~/.m2/toolchians.xml
中定义可以用的不同版本的JDK
。以后通常是使用version
这个属性来指定版本,有时也可以配合vendor
属性一同指定。
1<toolchains xmlns="http://maven.apache.org/TOOLCHAINS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2 xsi:schemaLocation="http://maven.apache.org/TOOLCHAINS/1.1.0 http://maven.apache.org/xsd/toolchains-1.1.0.xsd">
3 <toolchain>
4 <type>jdk</type>
5 <provides>
6 <version>1.8</version>
7 <vendor>zulu</vendor>
8 <purpose>development</purpose>
9 </provides>
10 <configuration>
11 <jdkHome>/Users/zhang/work/Devtools/jdk1.8.0</jdkHome>
12 </configuration>
13 </toolchain>
14
15 <toolchain>
16 <type>jdk</type>
17 <provides>
18 <version>11</version>
19 <vendor>zulu</vendor>
20 <purpose>development</purpose>
21 </provides>
22 <configuration>
23 <jdkHome>/Users/zhang/work/Devtools/jdk17</jdkHome>
24 </configuration>
25 </toolchain>
26
27</toolchains>
2.2 pom.xml
然后在项目pom.xml
文件中,使用maven-toolchains-plugin
来指定JDK
版本。以下例子指定了必须使用jdk1.8
。
1<build>
2 <plugins>
3 <plugin>
4 <groupId>org.apache.maven.plugins</groupId>
5 <artifactId>maven-toolchains-plugin</artifactId>
6 <version>3.2.0</version>
7 <executions>
8 <execution>
9 <goals>
10 <goal>toolchain</goal>
11 </goals>
12 </execution>
13 </executions>
14 <configuration>
15 <toolchains>
16 <jdk>
17 <version>1.8</version>
18 </jdk>
19 </toolchains>
20 </configuration>
21 </plugin>
22 </plugins>
23</build>
也可以使用如下的方式指定JDK
的版本范围:
1 <configuration>
2 <toolchains>
3 <jdk>
4 <version>[1.8,)</version>
5 </jdk>
6 </toolchains>
7 </configuration>
或者与vendor
一起联合更加精确的指定JDK:
1 <configuration>
2 <toolchains>
3 <jdk>
4 <version>1.8</version>
5 <vendor>zulu</vendor>
6 </jdk>
7 </toolchains>
8 </configuration>