Java9模块化学习笔记三之迁移到Java9

news/2025/3/22 1:55:49

java[c]命令行参数文件

鉴于迁移到java9后可能需要很长的命令行参数,有些os会限制命令行长度,java9支持定义一个命令行参数文件。使用方式:

java @arguments.txt

arguments.txt内容(每个选项一行):

-cp application.jar:javassist.jar
--add-opens java.base/java.lang=ALL_UNNAMED
--add-exports java.base/sun.security.x509=ALL_UNNAMED
-jar application.jar

Jdeps

前面我们说过以前很多时候我们或第三方库使用jdk不推荐使用的内部类,比如sun.,jdk.internal.,在jdk9之后这些类被强封装了,为了保持兼容性,默认运行运行时访问,其行为可以通过java选项--illegal-access=值,控制,默认值为permit,其他可选值有warn,debug,deny

除此之外还有些类被移除了,比如sun.misc.Base64Decoder/Base64Encoder, 不过提供了替代方案java.util.Encoder
我们可以借助于jdeps工具来发现这些问题,使用方式:

jdeps -jdkinternals Xxx.class

注意:jdeps只能用于分析class文件或jar,不能用于分析源码文件

使用jdeps分析 classpath-based依赖:
.
├── jars
│ ├── jackson-annotations-2.8.8.jar
│ └── jackson-core-2.8.8.jar
| └── jackson-databind-2.8.8.1.jar
└── out

 ├── demo├── Book.class└── Main.class

比如分析上面的这个模块:

jdeps -recursive -summary -cp lib/*.jar out

-recusive代表requires transitive的也会被分析,-summary代表汇总依赖信息,不然会打印很长的依赖信息, -cp classpath, out就是需要被分析的class/jar文件路径

tjw$ jdeps -recursive -summary -cp lib/*.jar out
jackson-annotations-2.8.8.jar -> java.base
jackson-core-2.8.8.jar -> java.base
jackson-databind-2.8.8.jar -> lib/jackson-annotations-2.8.8.jar
jackson-databind-2.8.8.jar -> lib/jackson-core-2.8.8.jar
jackson-databind-2.8.8.jar -> java.base
jackson-databind-2.8.8.jar -> java.desktop
jackson-databind-2.8.8.jar -> java.logging
jackson-databind-2.8.8.jar -> java.sql
jackson-databind-2.8.8.jar -> java.xml
out -> lib/jackson-databind-2.8.8.jar
out -> java.base

上面的依赖分析显示,我们的代码直接依赖jackson-databind,故而我们在迁移到模块时应将jackson-databind作为Automic Module,故而迁移到模块化后的代码结构如下:
.
├── lib
│ ├── jackson-annotations-2.8.8.jar
│ └── jackson-core-2.8.8.jar
├── mods
│ └── jackson-databind-2.8.8.jar //这里会被作为Automic Module
└── src

└── books├── demo│   ├── Book.java│   └── Main.java└── module-info.java

module-info.java内容:

module books {requires jackson.databind;opens demo;
}

使用jdeps分析 module-based依赖:
jdeps -module-path out:mods -m books

注意:使用jdeps我们还可以利用-dotoutput选项来输出模块的依赖关系图作为文件保存

除了分析依赖之外,jdeps还可以生成module-info.java,这在迁移已有三方库的时候特别有用:

jdeps --generate-module-info ./out mylibrary.jar

JAXB与其他JavaEE API

java.se.ee模块
clipboard.png

Automatic Modules

除了之前说的unamed modules,还有一种叫automatic modules,这是为解决已有三方库迁移到模块化的问题。已有三分库可以自动转成模块,只要在启动时将jar放在指定--module-path路径中,便会自动变成automatic module。
automatic module的特性:1、该module本身是open的;2、该module的依赖由开发者自行解决,编译时无法找出相关问题;3、automatic module与explicit module的区别在于,前者可以无限制访问unamed module,而后者遵循模块的封装性原则。
automatic modules模块名: 比如jackson-databind-2.8.8.jar,在java定义它成模块时,首先需要扫描MATA-INF/MANIFEST.MF中的Automatic-Module-Name字段,如果没有这个字段,那么就以jar文件名字作为模块名,比如jackson-databind-2.8.8.jar的模块名就是jackson.databind,转成模块名时会把-替换成. 然后版本号会被忽略掉。

clipboard.png

迁移示例:迁移Spring And Hibernate

未迁移代码就不列出来了,迁移后的代码结构如下:

.
├── README.md
├── lib
│   ├── hsqldb-2.3.4.jar
│   ├── ...
│   ├── slf4j-api-1.7.21.jar
│   ├── slf4j-simple-1.7.21.jar
│   ├── spring-aop-4.3.2.RELEASE.jar
│   ├── spring-beans-4.3.2.RELEASE.jar
│   ├── spring-core-4.3.2.RELEASE.jar
│   ├── spring-expression-4.3.2.RELEASE.jar
│   ├── spring-jdbc-4.3.2.RELEASE.jar
│   └── spring-orm-4.3.2.RELEASE.jar
├── mods
│   ├── hibernate-core-5.2.2.Final.jar
│   ├── hibernate-jpa-2.1-api-1.0.0.Final.jar
│   ├── javassist-3.20.0-GA.jar
│   ├── javax.inject-1.jar
│   ├── spring-context-4.3.2.RELEASE.jar
│   └── spring-tx-4.3.2.RELEASE.jar
├── run.sh
└── src└── bookapp├── books│   ├── api│   │   ├── entities│   │   │   └── Book.java│   │   └── service│   │       └── BooksService.java│   └── impl│       ├── entities│       │   └── BookEntity.java│       └── service│           └── HibernateBooksService.java├── bookstore│   ├── api│   │   └── service│   │       └── BookstoreService.java│   └── impl│       └── service│           └── BookstoreServiceImpl.java├── log4j2.xml├── main│   └── Main.java├── main.xml└── module-info.java

module-info.java内容

module bookapp {requires spring.context;requires spring.tx;requires javax.inject;requires hibernate.core;requires hibernate.jpa;exports books.api.entities;exports books.api.service;opens books.impl.entities;opens books.impl.service;exports bookstore.api.service;opens bookstore.impl.service;
}

run.sh内容

CP=lib/antlr-2.7.7.jar:
...
CP+=lib/slf4j-api-1.7.21.jar:
CP+=lib/slf4j-simple-1.7.21.jar:
CP+=lib/spring-aop-4.3.2.RELEASE.jar:
CP+=lib/spring-beans-4.3.2.RELEASE.jar:
CP+=lib/spring-core-4.3.2.RELEASE.jar:
CP+=lib/spring-expression-4.3.2.RELEASE.jar:
CP+=lib/spring-jdbc-4.3.2.RELEASE.jar:
CP+=lib/spring-orm-4.3.2.RELEASE.jar$JAVA_HOME/bin/javac -cp $CP \--module-path mods \--add-modules java.naming \-d out         \--module-source-path src \-m bookappcp $(find src -name '*.xml') out/bookapp$JAVA_HOME/bin/java -cp $CP \--module-path mods:out       \--add-modules java.xml.bind,java.sql \--add-opens java.base/java.lang=javassist \-m bookapp/main.Main

我们还可以将自己的应用拆分为多个模块
演化图如下:
clipboard.png
clipboard.png
clipboard.png

迁移Library到模块化

迁移方式一,迁移为Automatic Module,适用于没有源码的情形:
模块名:在MANIFEST.MF中定义

Automatic-Module-Name: com.javamodularity.modulename
jar -cfm mylibrary.jar META-INF/MANIFEST.MF -C out/ .

你也可以使用maven插件

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><configuration><archive><manifestEntries><Automatic-Module-Namec>com.mymodule</Automatic-Module-Name></manifestEntries></archive></configuration>
</plugin>

迁移方式二,迁移为explicit module,适用于库的作者或者有源码的情形:
首先借助jdeps生成module-info.java,然后进行简单修改

jdeps --generate-module-info ./out mylibrary.jar  //你也可以使用--generate-open-module选项

方式三,迁移为explicit module,即使没有源码:

mkdir mylibrary
cd mylibrary
jar -xf ../mylibrary.jar
cd ..
javac -d mylibrary out/mylibrary/module-info.java
jar -uf mylibrary.jar -C mylibrary module-info.class

针对不同版本发布 javac --release 版本号 比如 javac --release 8

模块化开发工具

maven

.
├── README.md
├── algorithm.api
│   ├── pom.xml
│   └── src
│       └── main
│           └── java
│               ├── javamodularity
│               │   └── easytext
│               │       └── algorithm
│               │           └── api
│               │               ├── Analyzer.java
│               │               ├── Preprocessing.java
│               │               └── SyllableCounter.java
│               └── module-info.java
├── cli
│   ├── README.adoc
│   ├── pom.xml
│   └── src
│       └── main
│           ├── java
│           │   ├── javamodularity
│           │   │   └── easytext
│           │   │       └── cli
│           │   │           └── Main.java
│           │   └── module-info.java
│           └── resources
│               └── test.txt
├── gui
│   ├── gui.iml
│   ├── pom.xml
│   └── src
│       └── main
│           └── java
│               ├── javamodularity
│               │   └── easytext
│               │       └── gui
│               │           └── Main.java
│               └── module-info.java
├── pom.xml
└── run.sh
<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.6.1</version><configuration><release>9</release></configuration></plugin></plugins>
</build>

使用maven执行模块

  <build><plugins><plugin><groupId>org.codehaus.mojo</groupId><artifactId>exec-maven-plugin</artifactId><version>1.6.0</version><executions><execution><goals><goal>exec</goal></goals></execution></executions><configuration><executable>${JAVA_HOME}/bin/java</executable><arguments><argument>--module-path</argument><modulepath/><argument>--module</argument><argument>easytext.cli/javamodularity.easytext.cli.Main</argument><argument>${easytext.file}</argument></arguments></configuration></plugin></plugins></build>

具体执行命令 mvn exec:exec


https://dhexx.cn/news/show-1699716.html

相关文章

Typora添加数学公式

打开Typora的数学公式模块 点击“段落”—>“公式块” CtrlShiftm $$ enter 常用公式的代码 上/下标 算式Markdown$x^2 $x^2$y_1 $y_1 分式 算式Markdown1 / 2 1/21/21/21 2 \frac{1}{2}21\frac{1}{2} 省略号 省略号Markdown⋯ \cdots⋯\cdots 开根号 算式Markdow…

JS删除链表的节点

题目 给定单向链表的头指针和一个要删除的节点的值&#xff0c;定义一个函数删除该节点。 返回删除后的链表的头节点。 示例 1: 输入: head [4,5,1,9], val 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点&#xff0c;那么在调用了你的函数之后&#xff0c;该链表应…

一些音乐下的评论

总会想起在阿根廷的那些日子。远离小镇&#xff0c;一个人在湖边行走&#xff0c;目光越过巴塔哥尼亚高原枯黄低矮的灌木丛落在远处连绵不断的雪山上。眼前的湖面碧蓝如镜&#xff0c;倒映浮云。 我站在被称为世界尽头的地方&#xff0c;浮冰在海上缓慢漂动&#xff0c;浓雾在寒…

JS反转链表

题目&#xff1a;定义一个函数&#xff0c;输入一个链表的头节点&#xff0c;反转该链表并输出反转后链表的头节点。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL、解题思路&#xff1a; 当节点数为&#xff10;或者为&#…

Linux中文件的SUID、SGID、Sticky权限说明

1.SUID ​ 首先我们要了解&#xff0c;在Linux中启动一个程序或者启动一个进程是需要有用户的&#xff0c;一个文件的存在是要有用户和组的&#xff0c;一个进程启动后&#xff0c;它的属主取决于进程的发起者&#xff0c;比如 我用root用户启动了一个 cat 进程&#xff0c;那…

CentOS7下修改默认网卡名为eth0的两种方法

前言 大家都知道CentOS7默认的网卡名称是和设备名称是随机的&#xff0c;如果要修改网卡名称以 eth 开头&#xff0c;有两种方式&#xff0c;如下&#xff1a; 第一种方式 这种方式适合在安装操作系统的时候进行设置&#xff0c; 点击 Tab&#xff0c;打开kernel启动选项&#…

JS二叉树的深度

题目&#xff1a; 输入一棵二叉树的根节点&#xff0c;求该树的深度。从根节点到叶节点依次经过的节点&#xff08;含根、叶节点&#xff09;形成树的一条路径&#xff0c;最长路径的长度为树的深度。 例如&#xff1a; 给定二叉树 [3,9,20,null,null,15,7]&#xff0c; 返回它…

SpringBoot项目 部署到服务器的tomcat下

把spring-boot项目按照平常的web项目一样发布到tomcat容器下 一、修改pom文件 修改打包方式 修改或增加maven插件 注意&#xff1a; 二、移除嵌入式tomcat插件 三、添加servlet-api的依赖 <dependency><groupId>javax.servlet</groupId><artifactId>ja…

JS 在排序数组中查找数字 I (穷举法 二分法)

统计一个数字在排序数组中出现的次数。 示例 1: 输入: nums [5,7,7,8,8,10], target 8 输出: 2 示例 2: 输入: nums [5,7,7,8,8,10], target 6 输出: 0 方法一: 一开始想采取前面数组去重的方法&#xff0c;现将数组中每个数字出现的次数统计出来放在对象中&#xff0c;可以…

Python导入csv文件

共有三种方法&#xff0c;分别是通过标准的库函数、通过Numpy、通过Pandas。 1.通过标准Python库导入csv文件 Python提供了一个标准的类库CSV文件。这个类库中的reader()函数用来导入CSV文件。当CSV文件被读入后&#xff0c;可以利用这些数据生成一个NumPy数组&#xff0c;用…