前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >java9系列(八)Multi-Release JAR Files

java9系列(八)Multi-Release JAR Files

作者头像
code4it
发布2018-09-17 15:57:30
发布2018-09-17 15:57:30
1.2K00
代码可运行
举报
文章被收录于专栏:码匠的流水账码匠的流水账
运行总次数:0
代码可运行

本文主要研究下JEP 238: Multi-Release JAR Files

multi-release jar (MR JAR)

java9新支持了multi-release jar的功能,包括jar、javac、javap、jdeps等命令都能支持这个特性。所谓multi-release jar可以包含多个jdk版本的实现,在运行时JVM根据当前环境加载符合版本的class,这样可以使得jar包在兼容旧版本的同时尽可能早地尝试新版JDK的特性。

具体的变化就是META-INF目录下MANIFEST.MF文件新增了一个属性:

代码语言:javascript
代码运行次数:0
运行
复制
Multi-Release: true

然后META-INF目录下还新增了一个versions目录,如果是要支持java9,则在versions目录下有9的目录

实例

java8

  • com.example.lang
代码语言:javascript
代码运行次数:0
运行
复制
public class StackHelper {

    public static String getCurrentStack() {
        System.out.println("java 8 stack");
        return Arrays.stream(Thread.currentThread()
                .getStackTrace())
                .map(element -> element.toString())
                .collect(Collectors.joining("\n"));
    }
}
  • maven
代码语言:javascript
代码运行次数:0
运行
复制
    <groupId>com.example</groupId>
    <artifactId>mr-jar-java</artifactId>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>mr-jar-java9</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifestEntries>
                            <Specification-Title>${project.artifactId}</Specification-Title>
                            <Implementation-Title>${project.artifactId}</Implementation-Title>
                            <Implementation-Version>${project.version}</Implementation-Version>
                            <Multi-Release>true</Multi-Release>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>add-java9-classes</id>
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>unpack-dependencies</goal>
                        </goals>
                        <configuration>
                            <includeGroupIds>com.example</includeGroupIds>
                            <includeArtifactIds>mr-jar-java9</includeArtifactIds>
                            <excludeTransitives>true</excludeTransitives>
                            <outputDirectory>${project.build.directory}/generated-resources/META-INF/versions/9</outputDirectory>
                            <includes>**/*.class</includes>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <version>3.0.0</version>
                <executions>
                    <execution>
                        <id>add-resource</id>
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>add-resource</goal>
                        </goals>
                        <configuration>
                            <resources>
                                <resource>
                                    <directory>${project.build.directory}/generated-resources/</directory>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

注意,这里依赖java9的jar包,然后Multi-Release设置为true,通过编译打包把java9的classes放到META-INF/versions/9目录下,原来java8的classes位置不变。

java9

  • com.example.lang
代码语言:javascript
代码运行次数:0
运行
复制
public class StackHelper {

    public static String getCurrentStack() {
        System.out.println("java 9 stack");
        return StackWalker.getInstance()
                .walk(frames -> frames.map(Object::toString)
                        .collect(joining("\n")));
    }
}
  • module-info.java
代码语言:javascript
代码运行次数:0
运行
复制
module mr.jar.java9 {
    exports com.example.lang;
}
  • maven
代码语言:javascript
代码运行次数:0
运行
复制
    <groupId>com.example</groupId>
    <artifactId>mr-jar-java9</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.target>9</maven.compiler.target>
        <maven.compiler.source>9</maven.compiler.source>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.2</version>
                <configuration>
                    <release>9</release>
                </configuration>
            </plugin>
        </plugins>
    </build>

打包

代码语言:javascript
代码运行次数:0
运行
复制
mvn clean install
  • jar包内容如下
代码语言:javascript
代码运行次数:0
运行
复制
➜  mr-jar-java-0.0.1-SNAPSHOT git:(master) ✗ tree
.
├── META-INF
│   ├── MANIFEST.MF
│   ├── maven
│   │   └── com.example
│   │       └── mr-jar-java
│   │           ├── pom.properties
│   │           └── pom.xml
│   └── versions
│       └── 9
│           ├── com
│           │   └── example
│           │       └── lang
│           │           ├── StackHelper.class
│           │           └── StringHelper.class
│           └── module-info.class
└── com
    └── example
        └── lang
            ├── StackHelper.class
            └── StringHelper.class

12 directories, 8 files
  • 查看MANIFEST.MF
代码语言:javascript
代码运行次数:0
运行
复制
Manifest-Version: 1.0
Created-By: Apache Maven 3.3.3
Built-By: demo
Build-Jdk: 9
Implementation-Title: mr-jar-java
Implementation-Version: 0.0.1-SNAPSHOT
Multi-Release: true
Specification-Title: mr-jar-java
  • 确认java8 class版本
代码语言:javascript
代码运行次数:0
运行
复制
➜  mr-jar-java-0.0.1-SNAPSHOT git:(master) ✗ javap -verbose ./com/example/lang/StackHelper.class
Classfile /Users/demo/multi-release-jar-demo/mr-jar-java8/target/mr-jar-java-0.0.1-SNAPSHOT/com/example/lang/StackHelper.class
  Last modified 2018年3月7日; size 1901 bytes
  MD5 checksum 9fafe51ca3df481e8c2264753c281a9a
  Compiled from "StackHelper.java"
public class com.example.lang.StackHelper
  minor version: 0
  major version: 52
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #15                         // com/example/lang/StackHelper
  super_class: #16                        // java/lang/Object
  interfaces: 0, fields: 0, methods: 3, attributes: 3

可以看到major版本是52

  • 确认java9 class版本
代码语言:javascript
代码运行次数:0
运行
复制
➜  mr-jar-java-0.0.1-SNAPSHOT git:(master) ✗ javap -verbose ./META-INF/versions/9/com/example/lang/StackHelper.class
Classfile /Users/demo/multi-release-jar-demo/mr-jar-java8/target/mr-jar-java-0.0.1-SNAPSHOT/META-INF/versions/9/com/example/lang/StackHelper.class
  Last modified 2018年3月7日; size 1921 bytes
  MD5 checksum da6326681eb1b0584998a92178e22e27
  Compiled from "StackHelper.java"
public class com.example.lang.StackHelper
  minor version: 0
  major version: 53
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #14                         // com/example/lang/StackHelper
  super_class: #15                        // java/lang/Object
  interfaces: 0, fields: 0, methods: 3, attributes: 3

可以看到major版本是53

运行

  • java8
代码语言:javascript
代码运行次数:0
运行
复制
java 8 stack
java.lang.Thread.getStackTrace(Thread.java:1559)
com.example.lang.StackHelper.getCurrentStack(StackHelper.java:14)
Java8Main.main(Java8Main.java:15)
  • java9
代码语言:javascript
代码运行次数:0
运行
复制
java 9 stack
mr.jar.java9/com.example.lang.StackHelper.getCurrentStack(StackHelper.java:13)
mr.jar.java9.main/mr.jar.java9.main.Java9Main.main(Java9Main.java:17)

注意java9调用multi-release jar的工程,需要requires该module,然后编译运行都需要添加module-path

代码语言:javascript
代码运行次数:0
运行
复制
java --module-path ./target/classes:/Users/demo/.m2/repository/com/example/mr-jar-java/0.0.1-SNAPSHOT/mr-jar-java-0.0.1-SNAPSHOT.jar --module mr.jar.java9.main/mr.jar.java9.main.Java9Main

jar命令

上面的例子是利用maven插件来打包,也可以使用jar来打包multi-release jar,实例如下:

代码语言:javascript
代码运行次数:0
运行
复制
javac --release 8 -d out/8 mr-jar-java8/src/main/java/com/example/lang/StackHelper.java
javac --release 9 -d out/9 mr-jar-java9/src/main/java/com/example/lang/StackHelper.java
jar -cfm out/mr-jar-demo.jar ./MANIFEST.MF -C out/8 .
jar -uf out/mr-jar-demo.jar --release 9 -C out/9 .

这里的-c表示创建jar包,-C表示转去该目录执行不带-C的jar命令,-f指定jar包的文件名,-m指定manifest.mf文件,-u添加文件到jar包中 其中MANIFEST.MF包含Multi-Release: true

小结

java9提供的multi-release jar的功能,可以在一个jar包打入多个jdk版本,同时在java9及以上的版本支持multi-release。它的好处就是比如从java8到java9的迁移,如果java8依赖的jar本身就是multi-release的,那么升级到java9就比较方便,不用再改maven依赖。不好的地方就是有过度设计的味道,一个jar包含多个版本的class,显得有些冗余。

doc

  • JDK 9 features
  • JEP 238: Multi-Release JAR Files
  • Building Multi-Release JARs with Maven
  • Multi-Release JARs: Good or Bad Idea?
  • Creating Multi-Release JAR Files in IntelliJ IDEA
  • The (Practical) Truth about Multi-Release JARs
  • Understanding Java 9 Multi-Release Jar File with Example
  • Multi-Release JARs: Good or Bad Idea?
  • Java 9 - Multi-Release Jar Example
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-03-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码匠的流水账 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • multi-release jar (MR JAR)
  • 实例
    • java8
    • java9
    • 打包
    • 运行
  • jar命令
  • 小结
  • doc
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档