java9系列(八)Multi-Release JAR Files

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

multi-release jar (MR JAR)

java9新支持了multi-release jar的功能,包括jar、javac猬膨、javap、jdeps等命令都能支持這個(gè)特性狸涌。所謂multi-release jar可以包含多個(gè)jdk版本的實(shí)現(xiàn),在運(yùn)行時(shí)JVM根據(jù)當(dāng)前環(huán)境加載符合版本的class最岗,這樣可以使得jar包在兼容舊版本的同時(shí)盡可能早地嘗試新版JDK的特性。

通過--release參數(shù)指定編譯版本朝捆,依賴JEP 247: Compile for Older Platform Versions來編譯成指定JDK版本的class

具體的變化就是META-INF目錄下MANIFEST.MF文件新增了一個(gè)屬性:

Multi-Release: true

然后META-INF目錄下還新增了一個(gè)versions目錄般渡,如果是要支持java9,則在versions目錄下有9的目錄

實(shí)例

java8

  • com.example.lang
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
    <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設(shè)置為true,通過編譯打包把java9的classes放到META-INF/versions/9目錄下儒老,原來java8的classes位置不變蝴乔。

java9

  • com.example.lang
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
module mr.jar.java9 {
    exports com.example.lang;
}
  • maven
    <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>

打包

mvn clean install
  • jar包內(nèi)容如下
?  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
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
  • 確認(rèn)java8 class版本
?  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

  • 確認(rèn)java9 class版本
?  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

運(yùn)行

  • java8
java 8 stack
java.lang.Thread.getStackTrace(Thread.java:1559)
com.example.lang.StackHelper.getCurrentStack(StackHelper.java:14)
Java8Main.main(Java8Main.java:15)
  • java9
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調(diào)用multi-release jar的工程,需要requires該module驮樊,然后編譯運(yùn)行都需要添加module-path

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,實(shí)例如下:

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表示創(chuàng)建jar包囚衔,-C表示轉(zhuǎn)去該目錄執(zhí)行不帶-C的jar命令挖腰,-f指定jar包的文件名,-m指定manifest.mf文件练湿,-u添加文件到j(luò)ar包中
其中MANIFEST.MF包含Multi-Release: true

小結(jié)

java9提供的multi-release jar的功能猴仑,可以在一個(gè)jar包打入多個(gè)jdk版本,同時(shí)在java9及以上的版本支持multi-release肥哎。它的好處就是比如從java8到j(luò)ava9的遷移辽俗,如果java8依賴的jar本身就是multi-release的疾渣,那么升級(jí)到j(luò)ava9就比較方便,不用再改maven依賴崖飘。不好的地方就是有過度設(shè)計(jì)的味道榴捡,一個(gè)jar包含多個(gè)版本的class,顯得有些冗余坐漏。

doc

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末薄疚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子赊琳,更是在濱河造成了極大的恐慌街夭,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件躏筏,死亡現(xiàn)場(chǎng)離奇詭異板丽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)趁尼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門埃碱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人酥泞,你說我怎么就攤上這事砚殿。” “怎么了芝囤?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵似炎,是天一觀的道長。 經(jīng)常有香客問我悯姊,道長羡藐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任悯许,我火速辦了婚禮仆嗦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘先壕。我一直安慰自己瘩扼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布启上。 她就那樣靜靜地躺著邢隧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪冈在。 梳的紋絲不亂的頭發(fā)上倒慧,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼纫谅。 笑死炫贤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的付秕。 我是一名探鬼主播兰珍,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼询吴!你這毒婦竟也來了掠河?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤猛计,失蹤者是張志新(化名)和其女友劉穎唠摹,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奉瘤,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡勾拉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盗温。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片藕赞。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖卖局,靈堂內(nèi)的尸體忽然破棺而出斧蜕,到底是詐尸還是另有隱情,我是刑警寧澤砚偶,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布惩激,位于F島的核電站,受9級(jí)特大地震影響蟹演,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜顷蟀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一酒请、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鸣个,春花似錦羞反、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至涛舍,卻和暖如春澄惊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來泰國打工掸驱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肛搬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓毕贼,卻偏偏與公主長得像温赔,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鬼癣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理陶贼,服務(wù)發(fā)現(xiàn),斷路器待秃,智...
    卡卡羅2017閱讀 134,656評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,811評(píng)論 6 342
  • 1.編寫POM Maven項(xiàng)目的核心文件是pom.xml拜秧,POM(Project Objcet Model)項(xiàng)目對(duì)...
    zlcook閱讀 5,908評(píng)論 7 26
  • 恍惚間離開家鄉(xiāng)已有近十年的時(shí)間。家鄉(xiāng)是晉南稷山縣锥余,汾河?xùn)|西流經(jīng)稷山腹纳,自然地經(jīng)稷山分為南北兩部分,所以老家人又習(xí)慣性...
    浪雨晴閱讀 854評(píng)論 4 5
  • 對(duì)我來說驱犹,這次1千公里外的北京之行是我第一次出遠(yuǎn)門嘲恍,在我寫這篇文字的時(shí)候,心始終半懸著雄驹,盡管我一直在提醒自己這可是...
    肖卡夫卡閱讀 272評(píng)論 0 1