边实验边分析-Maven默认选择JDK规则以及如何使用指定JDK版本进行编译
Maven默认使用的是JAVA_HOME的环境变量来找到Java环境进行编译的,官网上有明确说明
其说明了maven会找JAVA_HOME和Path里面的Java配置,这边可能有人会问了,那如果我配了多个Java环境的情况会如何?最好的办法我们自己实践一下,这边我把我的实践结果告诉大家:
- 配置了JAVA_HOME, 则会优先选择该环境配置,并且如果你的JAVA_HOME环境是一个错误的环境,则执行maven插件的时候会直接报错。
- 未配置JAVA_HOME, 则会找Path里面的环境配置,并且如果你的Path里面还配置了多个Java可执行环境,则会按照先后顺序进行选择。
- 如果都未配置,则直接报错。
上面说到的都是maven的默认行为,那么我们是否可以自己指定maven用哪个java版本进行编译呢?这边官网也给出了2种方式https://maven.apache.org/plugins/maven-compiler-plugin/examples/compile-using-different-jdk.html,具体是:
一种是使用工具链指定,这边给出官网地址:https://maven.apache.org/guides/mini/guide-using-toolchains.html,这种方式比较复杂一点,但是是官方推荐的,其优点是可以全局对编译插件进行设置,这边不展开讲这种方式,官网已经比较详细说明了用法。
另一种是我们可以强制对某一插件进行指定,在这里我们直接对compile插件进行强制的配置,来指定我们想要使用的JDK版本,如下
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<fork>true</fork>
<executable>${JAVA_HOME_HIGH}\bin\javac</executable>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
我们直接配置executable为一个高版本的JDK中的javac,我们使用了一个环境变量JAVA_HOME_HIGH来避免将路径写死,并且我们配置fork为true,这样才能使得executable属性生效。
关于compilerVersion属性,实验发现,该属性只作用于该插件,并不会影响到我们编译项目使用的JDK版本。
以上则是Maven如何使用不同的JDK版本对我们的项目进行编译的方式,另外,我们即使使用同一个JDK版本进行编译,我们也能够指定不同的JDK版本,这需要归功于Javac的-source
和 -target
这两个参数,通过这两个参数,我们可以指定编译的目标版本和编译的兼容版本,在maven的pom文件里,我们可以加入这两个配置
<project>
[...]
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>8</maven.compiler.target>
<maven.compiler.source>8</maven.compiler.source>
</properties>
[...]
</project>
这边我们指定了source和target为8,即Java1.8,这样,即使我们像上面一样指定了使用JAVA 11的JDK进行编译,maven在编译的时候也会为我们加上-source和-target参数,我们可以使用mvn compile -X -f “path.pom” 命令来查看具体的编译debug日志输出,可以找到如下图:
这样我们就完成了,另外这边需要注意,你在设置-source和-target参数的时候一定要保证maven在使用的JDK版本支持,不然也会编译失败哦。
另外记录一个在项目中发生的问题,也是这个问题导致了上面的这些研究,最近有个项目使用maven作为编译工具,使用VSCode进行开发,使用了okhttp版本为3.14.9,由于本身是个库,所以将okhttp源码导入进了库中,以免与使用方冲突,在编译项目的时候,使用了1.8.0_144的JDK进行编译,发现会报错,在Android10Platform的类中,JAVAX库的SSLSocket类中getApplicationProtocol方法会找不到(还有一个setApplicationProtocols一样找不到),查了API文档,发现这个方法的记载有些好玩,在JAVA1.8的API文档上写的1.8支持,但是在1.9的文档上又写了1.9才支持这个方法,但是问题确实是有,所以使用了java11版本,指定1.8进行编译,编译通过了。但后来在打包机上发现,openJDK 1.8.0.282版本里面是有这个方法的,只是该方法没实现而已,附上我自己找的JDK中的rt.jar里面看到的1.8.0_144和openJDK 1.8.0.282里面这个方法的差别:
上图是从1.8.0_144的rt.jar
这个是openJDK 1.8.0.282里面拿到的。着实有点坑。