跨版本 Java 开发的必要性
- 兼容性需要,现有服务器只支持较老版本 Java,只好继续支持遗留的系统
最近接了一个程序开发项目,程序运行的服务器为window server 2003,32位操作系统。当时看到这个版本,差点没把一口血吐出来。
这个项目好在测试到最后,操作系统支持jdk1.8初始版本。这样可以使用新的jdk指定低版本1.8的java api代码风格完成代码编写,再使用1.8初始版本的javac和jar去编译与打包成目标jar包,并提交操作系统运行。
- 可移植性需要
虽然java的代码编译一次之后,可以在任何java虚拟机上面运行,但是新的编译器编译出来的代码会有一个最低的可运行jre版本指定,如果java启动的时候,这个条件不满足,则会报最低java不满足条件的报错,并退出运行。比如这个项目,生产运行的是1.6,而大部分jar最低到1.8版本可运行,则需要重新使用javac1.6重新编译并打包,如果有多版本开发,则修改一个参数即可完成编译打包,代码修改量比较少。
多JDK所涉及的层面
开发层面
编写代码的过程,其实跟版本无关,主要是要考虑到用哪个版本的javac编译而用哪个级别的代码风格来编写代码,另外编写代码所用的工具链运行JDK版本,如lint工具所需要的代码级别、智能代码提示所需要的代码级别和jdk代码库,尽可能使用低级别的代码风格来编写jar库,这样才能支持更多的运行环境,编写完成之后,直接指定最低的运行级别,这里建议与大部分jar库一致指定最低1.8。
编译运行层面
运行需要指定相应级别的JDK/JRE来运行代码字节码,并且,程序所依赖的jar库需要满足最低运行级别,否则会报所运行的级别不支持。在这个层面基本只涉及javac和java程序,即相应JDK版本的javac和java,前者负责编译,后面负责运行。
编译打包层面
代码编写完成之后,打包成对应的jar/war包,编译依赖于javac的版本,打包依赖于jar.exe的版本,但打包理论上应该跟版本无关,jar包只是一个带了元数据的压缩包而已。
如何实现跨版本编译和打包
由于习惯使用maven这个工具来管理程序依赖并进行编译与打包,以下都是maven的案例。
- 准备多个不同版本的 JDK
比如1.5、1.6、1.8、11、17等等,比如我的环境就有这么多个版本
- 准备好
toolchains.xml
,并把它放到~/.m2/toolchains.xml
,内容如下
<?xml version="1.0" encoding="UTF-8"?>
<toolchains>
<!-- JDK toolchains -->
<toolchain>
<type>jdk</type>
<provides>
<version>1.6</version>
<vendor>sun</vendor>
</provides>
<configuration>
<jdkHome>C:\Users\wisfern\.jdks\jdk1.6.0_45_32</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<version>1.8</version>
<vendor>sun</vendor>
</provides>
<configuration>
<jdkHome>C:\Users\wisfern\.jdks\jdk1.8.0_202_32</jdkHome>
</configuration>
</toolchain>
</toolchains>
有多少个jdk,就准备多少项toolchain
,这里只准备两个,是因为其他更高级别的版本,暂时没遇到使用的地方。
- 在 pom.xml 文件中设置编译器级别
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
<maven.toolchain.jdk.version>1.6</maven.toolchain.jdk.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-toolchains-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<goals>
<goal>toolchain</goal>
</goals>
</execution>
</executions>
<configuration>
<toolchains>
<jdk>
<version>${maven.toolchain.jdk.version}</version>
<vendor>sun</vendor>
</jdk>
</toolchains>
</configuration>
</plugin>
</plugins>
</build>
<java.version>
指定用于编译和运行该项目的 Java 版本。在这种情况下,它设置为 1.8。 <maven.compiler.source>
指定用于编译源代码的语言级别。这里,它设置为 1.6,这意味着代码必须与 Java 6 语法兼容。 <maven.compiler.target>
指定编译后的代码应兼容的 Java 字节码版本。这里也设置为 1.6,这意味着编译后的代码应该可以在 Java 6 运行时环境上运行。 <maven.toolchain.jdk.version>
指定构建项目时要使用的 JDK 版本。在这里,它设置为 1.6,这意味着构建应该使用 JDK 6,并且这个参数在maven-toolchains-plugin
插件引用,设置了插件所调用的编译与打包工具链。
- 做完以上就可以操作
maven package -X
-X 启用更详细的日志输出,这样就可以在日志看到所调用的javac和jar的路径。
兼容性问题处理
unsupport class version
- 版本间兼容性问题
- 升级 Java 版本带来的应用程序修改
- 使用第三方库时的版本兼容性问题