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模块
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,转成模块名时会把-
替换成.
然后版本号会被忽略掉。
迁移示例:迁移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 bookapp
cp $(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
我们还可以将自己的应用拆分为多个模块
演化图如下:
迁移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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。