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.mzph.cn/bicheng/59982.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二叉树的前中后序遍历

前序遍历:中左右 中序遍历:左中右 后序遍历:左右中 递归法:三种遍历方式代码结构相似&#xff0c;需要搞清楚三个内容:递归函数的返回值&#xff0c;递归函数传递的参数以及递归函数结束的条件 代码随想录 迭代法:需要用栈实现&#xff0c;前序和后序类似&#xff0c;中序…

如何一步步实现api接入JD平台通过url获取item get商品详情字段信息

以下是一步步实现通过 API 接入京东&#xff08;JD&#xff09;平台并使用 URL 获取商品详情&#xff08;Item Get&#xff09;字段信息的大致步骤&#xff1a; 一、注册成为京东开发者并获取 API 权限 注册开发者账号 访问京东api文档&#xff0c;点击注册按钮&#xff0c;按照…

Ubuntu笔记-auto remove

apt autoremove确实是一个非常有用的命令&#xff0c;它用于自动删除系统中不再需要的依赖包。这些依赖包通常是在安装某些软件时自动安装的附加包&#xff0c;而当这些软件被卸载后&#xff0c;这些依赖包也就失去了作用。 然而&#xff0c;许多博客和用户提醒说 apt autorem…

机器视觉基础—双目相机

机器视觉基础—双目相机与立体视觉 双目相机概念与测量原理 我们多视几何的基础就在于是需要不同的相机拍摄的同一个物体的视场是由重合的区域的。通过下面的这种几何模型的目的是要得到估计物体的长度&#xff0c;或者说是离这个相机的距离。&#xff08;深度信息&#xff09…

C++继承(图文非常详细)

继承的概念 1.什么是继承 1.简单定义 我们来看一下下面这串代码注意其中的两个类father 和 son using namespace std; #include<iostream> class father { public:void definity(){cout << "father" << endl;} protected:int tall 180;int age …

解决PyQt5多线程报错:QThread: Destroyed while thread is still running

在使用PyQt5进行多线程开发时&#xff0c;许多初学者会遇到一个常见的问题&#xff1a;程序在运行时没有任何明显的错误信息&#xff0c;但却在终端中报出QThread: Destroyed while thread is still running的警告。而在PyCharm等IDE中&#xff0c;只会看到Process finished wi…

Python中的数据类(dataclass):简化类的定义与数据管理的全面指南

解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! Python 3.7引入的数据类(dataclass)极大地简化了类的定义,尤其在处理数据管理任务时。数据类自动生成__init__、__repr__等方法,帮助开…

详细介绍MySQL、Mongo、Redis等数据库的索引

MySQL 索引 概念与类型 MySQL 索引是一种数据结构&#xff0c;用于快速查找数据库中的数据。它就像一本书的目录&#xff0c;通过索引可以快速定位到需要的数据行&#xff0c;而不必全表扫描。主要的索引类型包括 B - Tree 索引&#xff08;默认索引类型&#xff09;、哈希索引…

torch.full函数介绍

torch.full 是 PyTorch 中用于创建一个具有指定形状、填充值和数据类型的张量的函数。它非常适用于需要初始化特定数值的张量的情况,比如将所有元素填充为一个常量值。 函数定义 torch.full(size, fill_value, *, dtype=None, layout=torch.strided, device=None, requires_…

Unity自动打包——Shell交互

Unity 无论是测试还是上线都需要打包&#xff0c;而每次打包我们还要打各种平台&#xff08;安卓、Ios、WebGL、Windows…&#xff09;,有可能不同的打包时机还要有不同的配置项&#xff0c;这种工作枯燥、繁琐且易错&#xff0c;为了解决这一困扰就想到了能不能做一个工具来专…

NLP自然语言处理:深入探索Self-Attention——自注意力机制详解

NLP自然语言处理&#xff1a;深入探索Self-Attention——自注意力机制详解 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;自注意力机制&#xff08;Self-Attention&#xff09;已经成为一种革命性的技术&#xff0c;特别是在Transformer模型及其各种变种中得到了…

Tomcat中如何指定JDK版本

在Tomcat中指定JDK版本可以通过设置环境变量或修改启动脚本来实现。以下是两种常见的方法&#xff1a; 方法一&#xff1a;通过环境变量 设置JAVA_HOME环境变量&#xff1a; 打开“控制面板” -> “系统和安全” -> “系统” -> “高级系统设置”。点击“环境变量”按…

uniapp在js方法中,获取当前用户的uid(uni-id-user)表中的用户id

// 1.判断当前用的权限 let uid uniCloud.getCurrentUserInfo().uid //获取当前用户的uid // 用户uid等于发布者id或者用户权限等于admin或者用户角色等于webmaster if (uid this.item.user_id[0]._id || this.uniIDHasRole…

【机器学习】均方误差根(RMSE:Root Mean Squared Error)

均方误差根&#xff08;Root Mean Squared Error&#xff0c;RMSE&#xff09;是机器学习和统计学中常用的误差度量指标&#xff0c;用于评估预测值与真实值之间的差异。它通常用于回归模型的评价&#xff0c;以衡量模型的预测精度。 RMSE的定义与公式 给定预测值 和实际值 …

Pandas | 数据分析时将特定列转换为数字类型 float64 或 int64的方法

类型转换 传统方法astype使用value_counts统计通过apply替换并使用astype转换 pd.to_numericx对连续变量进行转化⭐参数&#xff1a;返回值&#xff1a;示例代码&#xff1a; isnull不会检查空字符串 数据准备 有一组数据信息如下&#xff0c;其中主要将TotalCharges、MonthlyC…

web信息收集

区别 CTF中&#xff0c;收集服务器信息、敏感信息、敏感文件 &#xff08;实战中&#xff0c;收集更多的信息来找到渗透的突破口&#xff0c;比如开放的端口、使用的CDN、是否有泄露的源码&#xff09; 一、收集信息 是了解一个web服务的首要途径&#xff0c;可以通过htt…

混沌工程遇上AI:智能化系统韧性测试的前沿实践

#作者&#xff1a;曹付江 文章目录 1、什么是AI驱动的混沌工程&#xff1f;2、AI与混沌工程结合的价值3、技术实现3.1 AI模型开发3.1.1模型选择与构建3.1.2模型训练3.1.3 模型验证与调参3.1.4 模型测试3.1.5 知识库建设与持续学习 4、混沌工程与AI实践结合4.1 利用AI从运维专家…

Redis的线程模型

Redis 的单线程模型详解 Redis 的“单线程”模型主要指的是其 主线程&#xff0c;这个主线程负责从客户端接收请求、解析命令、处理数据和返回响应。为了深入了解 Redis 单线程的具体工作流程&#xff0c;我们可以将其分为以下几个步骤&#xff1a; 接收客户端请求 Redis 的主线…

《深度学习神经网络:颠覆生活的魔法科技与未来发展新航向》

深度学习神经网络对我们生活的影响 一、医疗领域 深度学习神经网络在医疗领域的应用可谓意义重大。在疾病诊断方面&#xff0c;它能够精准分析医疗影像&#xff0c;如通过对大量的 CT、MRI 图像进行深度学习&#xff0c;快速准确地识别出微小的肿瘤病变&#xff0c;为医生提供…

YOLOv11融合特征细化前馈网络 FRFN[CVPR2024]及相关改进思路

YOLOv11v10v8使用教程&#xff1a; YOLOv11入门到入土使用教程 一、 模块介绍 论文链接&#xff1a;Adapt or Rerish 代码链接&#xff1a;https://github.com/joshyZhou/AST 论文速览&#xff1a;基于 transformer 的方法在图像恢复任务中取得了有希望的性能&#xff0c;因为…