当前位置: 首页 > article >正文

java:使用Multi-Release Jar改造Java 1.7项目增加module-info.class以全面合规Java 9模块化规范

common-java是一个我维护了好多年的一个基础项目,编译目标为Java 1.7
现在整个团队的项目要做Java 9以上的技术迁移准备,就需要对这个在内部各项目中被广泛引用的基础项目进行改造,以适合Java 9的模块化规范。

Automatic-Module-Name

Java 9的模块化规范(即Java Platform Module System [JPMS])要求在项目中有module-info.java,
会在module-info.java中定义模块名
module-info.java定义模块名示例如下

module your.module.name{
	//
}

JPMS可以兼容Java 1.7或1.8的依赖库.
在Java 9平台如果一个库没有module-info.class,那么会将它识别为自动模块(automatic module).会根据jar包的名字自动生成模块名(Module Name).
因为这个模块名是根据Jar包名字计算出来的,是不稳定的(比如手工改了Jar包文件名,模块名也会自动改为).
所以这不是JPMS建议的方式,所以在Java 9环境中引用自动模块时,编译过程会输出警告.

[WARNING] ******************************************************************************************************************************************************************************************************************************************************************************************************
[WARNING] * Required filename-based automodules detected: [guava-20.0.jar, jsr305-1.3.9.jar, fastjson-1.2.83.jar, jackson-databind-2.8.10.jar, jackson-core-2.8.10.jar, sql2java-base-3.29.3.jar, openbeans-1.0.2.jar, jcifs-ng-2.1.2.jar]. Please don’t publish this project to a public artifact repository! *
[WARNING] ******************************************************************************************************************************************************************************************************************************************************************************************************

对于一个编译目标为Java 1.7或1.8的项目,如果项目结构与Java 9的模块化要求不存在冲突.升级到Java 9并不复杂.
只要如下加一个maven-jar-plugin插件的配置,指定在生成Jar包中META-INF/MANIFEST.MF中增加Automatic-Module-Name定义,显式指定自动模块的名字.就可以让一个项目基本适合JPMS.可以正常被其他Java 9项目在module-info.java中引用。

	<build>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-jar-plugin</artifactId>
					<version>3.4.2</version>
					<configuration>
						<archive>
							<manifestEntries>
								<Automatic-Module-Name>your.module.name</Automatic-Module-Name>
							</manifestEntries>
						</archive>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>	
	</build>

Multi-Release Jar

采用上一节的方案生成的jar,在被Java 9项目引用时还会输出警告,示例如下:

[WARNING] /J:/javadocreader9/src/main/java/module-info.java:[7,34] 需要自动模块的过渡指令

引用自动模块报警的项目的module-info.java定义:

module com.gitee.l0km.javadocreader{
	exports com.gitee.l0km.javadocreader;
	requires java.desktop;
	requires transitive  jdk.javadoc;
	requires static com.google.common;
	requires transitive com4j.base2;
	requires transitive com4j.base;// [WARNING]:需要自动模块的过渡指令
	requires aocache;
	requires org.slf4j;
}

如果只是想消除这行警告,只需要将requires transitive com4j.base;改为requires static com4j.base;

也就是说对于一个Java 9项目如果module-info.java中引用了有Automatic-Module-Name定义了模块名的项目jar包,也仍然会有编译警告,它仍然不是JPMS满意的jar包.

要想让一个项目完全符合JPMS规范,就需要为它定义module-info.java,在module-info.java中显式定义项目的模块名,导出的包名等等.

参见 《Java 模块化指南》

定义module-info.java这本身不是问题.
问题在于我们的系统中还有一些android设备仍然在使用Java 1.7。
common-java这个项目也仍然被运行在这些Java 1.7的android设备上的APP引用.
如果增加module-info.java定义,项目的编译目标就要升级到Java 9,就不能用于Java 1.7的平台了.这肯定是不能接受的.

有没有一个两全其美的解决方案呢?

Multi-Release Jar (MRJAR)(多版本兼容Jar)是Java 9的一个新特性,就是为了解决这个麻烦而诞生的。
它允许将支持多个Java版本不特性的版本打包在同一个Jar包中,系统在运行时自动根据当前的Java版本,从Jar包选择对应Java版本的class加载.

即扩展 JAR 文件格式以允许多个特定于 Java 版本的 类文件的版本共存于单个存档(Jar)中。
详细说明参见:《JEP 238: Multi-Release JAR Files》

Multi-Release Jar (MRJAR)这个特性,事儿就好办了,还以common-java这个项目为例,分两个步骤:

(一) java.9

首先定义module-info.java
创建一个一个源文件夹${project.basedir}/src/main/java.9,在该文件夹下定义module-info.java
比如:

module com4j.base{
    exports com.gitee.l0km.com4j.base;
    exports com.gitee.l0km.com4j.base.encrypt;
    exports com.gitee.l0km.com4j.base.exception;
    exports com.gitee.l0km.com4j.base.web;

    requires static jackson.annotations;
}

(二)Multi-Release

更新pom.xml,如下增加maven-jar-pluginmaven-compiler-plugin插件定义

	<build>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<version>3.13.0</version>
					<executions>
						<execution>
							<id>default-compile-java-7</id>
							<goals>
								<goal>compile</goal>
							</goals>
							<configuration>
								<release>7</release>
								<compileSourceRoots>
									<compileSourceRoot>${project.basedir}/src/main/java</compileSourceRoot>
								</compileSourceRoots>
							</configuration>
						</execution>
						<execution>
							<id>compile-java-9</id>
							<goals>
								<goal>compile</goal>
							</goals>
							<configuration>
								<release>9</release>
								<compileSourceRoots>
									<compileSourceRoot>${project.basedir}/src/main/java.9</compileSourceRoot>
								</compileSourceRoots>
								<multiReleaseOutput>true</multiReleaseOutput>
							</configuration>
						</execution>
					</executions>
				</plugin>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-jar-plugin</artifactId>
					<version>3.4.2</version>
					<configuration>
						<archive>
							<manifestEntries>
								<Multi-Release>true</Multi-Release>
							</manifestEntries>
						</archive>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>

maven-jar-plugin插件中定义Multi-Release,即在生成的Jar中META-INF/MANIFEST.MF中定义Multi-Release为true,将Jar标志为支持Multi-Release.
maven-compiler-plugin插件中定义两个执行过程(<execution></execution>),
一个execution (default-compile-java-7)用于Java 1.7版本的编译,编译${project.basedir}/src/main/java源码文件夹下的所有主要代码.
另一个execution(compile-java-9)用于编译${project.basedir}/src/main/java.9,只有一个文件module-info.java,编译生成人代码保存到META-INF/versions/9,即Java 9对应的版本.

重新执行maven install生成的Jar包如下,Jar中除了:META-INF/versions/9/module-info.class外,主要代码代码的编译目标仍然为Java 1.7。因为有module-info.class提供模块定义,该Jar包在Java 9以上的平台上运行时,就是个符合JPMS要求的Module.
在这里插入图片描述
META-INF/MANIFEST.MF中定义如下:

Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.4.2
Build-Jdk-Spec: 19
Multi-Release: true

注意

如上改造了pom.xml后,不能再使用Java 1.7或1.8编译器构建项目,要使用Java 9以上编译器(我用的是Java 19)

common-java码云仓库位置:https://gitee.com/l0km/common-java

参考资料

《JDK 9 模块化系统 (Java Platform Module System) 和 多版本兼容 Jar (Multi-Release Jar)》

《JEP 238: Multi-Release JAR Files》

《Java 模块化指南》

《compiler:compile》
《Apache Maven JAR Plugin》


http://www.kler.cn/a/391767.html

相关文章:

  • 鸿蒙next版开发:相机开发-元数据(ArkTS)
  • Dial-insight:利用高质量特定领域数据微调大型语言模型防止灾难性遗忘
  • Springboot整合Prometheus+grafana实现系统监控
  • 人工智能的前沿研究方向与未来发展趋势
  • uni-app表单⑪
  • 51c视觉~合集6
  • Unet++改进24:添加DualConv||轻量级深度神经网络的双卷积核
  • 无人机飞手考证,地面站培训技术详解
  • uniCloud云对象调用第三方接口,根据IP获取用户归属地的免费API接口,亲测可用
  • PNG图片批量压缩exe工具+功能纯净+不改变原始尺寸
  • SpringBoot项目快速打包成jar项目与部署
  • 深入浅出《钉钉AI》产品体验报告
  • Spring Boot编程训练系统:架构设计精要
  • 虚拟机linux7.9下安装mysql遇到的问题
  • 计算机低能儿从0刷leetcode | 36.有效的数独
  • 【数学二】线性代数-向量-正交规范化、正交矩阵
  • 一篇文章学会ES6 Promise
  • 8 ARM-PEG-FA由八个臂状结构的聚乙二醇(PEG)核心与叶酸(FA)分子通过化学连接而成
  • 什么是大数据治理?在企业数字化转型过程中有什么用?
  • PostgreSQL存储过程-pgAdmin
  • 命令行工具进阶指南
  • 【 AI写作鹅-注册安全分析报告-无验证方式导致安全隐患】
  • Flutter下拉刷新上拉加载的简单实现方式二
  • Lucene 和 Elasticsearch 中更好的二进制量化 (BBQ)
  • 【网络安全 | 甲方建设】DDOS 防范教程
  • 用AI绘画一周赚1W?怎么用AI绘画赚钱!