Java 9 新特性 — 模块化Jar包(Multi-release JAR files)

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2018/03/10/java-9-multi-release-jar-files/

Java 9的特性有一个标号238的特性,链接如下:JEP 238: Multi-Release JAR Files

这个特性是有一定争议的,并没有在开源框架中大规模使用。

简而言之,多版本jar允许打包同一个类的多个版本,供不同运行时使用。 例如,如果在JDK 8上运行,Java运行时将使用该类的Java 8版本,但如果在Java 9上运行,它将使用Java 9特定的实现。同样,如果为Java 10版本构建版本,则运行时将使用它来代替Java 9和默认(Java 8)版本。

多版本JAR的用例

优化的运行时间

开发应用程序时,开发人员不知道将在哪个运行时执行。 但是对于某些运行时,可以实现相同类的优化版本。 例如通过查看java.version可以判断当前运行环境,然后通过一些技术手段来调用不同的实现。多版本Jar可以直接从JVM层提供这种特性的支持,不再需要自己实现。

冲突的API

例如需要支持2个不同的运行时,但有一个已弃用的API。 目前有两种广泛使用的解决方案:

最直接的方法是使用反射。 例如,可以定义一个VersionProvider接口,然后定义2个具体的类Java8VersionProvider和Java9VersionProvider ,它们是在运行时加载。 这个解决方案的一个变体是只有一个类,但是有不同的方法,通过反射访问和调用不同的方法。
如果技术上适用,更高级的解决方案是使用方法句柄。

还有一种常见的方案就是直接提供两个不同的jar文件,比如guava-jdk8和guava-jdk9。这个方法简单有效,但是管理这种代码库会带来一些难度。

多版本JAR的使用

Multi-release JAR files的关键在于MANIFEST.MF中,首先要声明

Multi-Release: true

然后提供不同版本的class文件,大概目录如下

Gradle作为常见的JVM平台项目构建工具,虽然目前没有对于多版本Jar的直接支持,但是由于灵活性大,可以直接自动配置一个。

首先是生成jar阶段

jar {
  into('META-INF/versions/9') {
     from sourceSets.java9.output
  }

  manifest.attributes(
     'Multi-Release': 'true'
  )
}

其次就是测试阶段,因为提供了多版本Jar,所以测试也应该有所针对

test {
   dependsOn jar
   def jdkHome = System.getenv("JAVA_8")
   classpath = files(jar.archivePath, classpath) - sourceSets.main.output
   executable = file("$jdkHome/bin/java")
   doFirst {
       println "$name runs test using JDK 8"
   }
}

task testJava9(type: Test) {
   dependsOn jar
   def jdkHome = System.getenv("JAVA_9")
   classpath = files(jar.archivePath, classpath) - sourceSets.main.output
   executable = file("$jdkHome/bin/java")
   doFirst {
       println classpath.asPath
       println "$name runs test using JDK 9"
   }

}

check.dependsOn(testJava9)

如果需要JDK10的支持也是一样的。

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2018/03/10/java-9-multi-release-jar-files/

发表评论