概述
Project Jigsaw:Module System Quick-Start Guide
http://openjdk.java.net/projects/jigsaw/quick-start
这篇文章提供了一个简单的示例,让开发者上手modules.
lunix系统中,文件路径使用/,分隔符使用:。Windows系统中,文件路径使用, ;作为路径分隔符。我这里的操作是在windows系统上。
Greetings
第一个例子是名为com.greetings的module。 它能够简单的打印出“Greetings!”。这个module由两个源文件组成:module的声明(module-info.java)和main文件。
按照约定,模块的源码所在的目录是这个模块的名称。
src/com.greetings/com/greetings/Main.java
package com.greetings;
public class Main {
public static void main(String[] args) {
System.out.println("Greetings!");
}
}
src/com.greetings/module-info.java
module com.greetings {}
使用如下的命令行,将源文件编译放到mods/com.greetins中:
E:>javac -d modscom.greetings srccom.greetingsmodule-info.java srccom.gre
etingscomgreetingsMain.java
E:>
这里会自动创建modscom.greetings文件目录,我们使用如下命令来运行:
E:>java –module-path mods -m com.greetings/com.greetings.Main
Greetings!
E:>
可以看到控制台输出了Greetings!
–module-path是module的路径一个或者多个包含modules的目录。
-m是可选项,它指定主模块,斜杠后面的值是module里面的主类名。
Greetings world
第二个例子修改了module声明,它声明了module org.astro.Module的依赖,同时输出org.astro的API.
src/org.astro/module-info.java
module org.astro{
exports org.astro;
}
src/org.astro/org/astro/World.java
package org.astro;
public class World {
public static String name() {
return "world";
}
}
src/com.greetins/com/greetings/Main.java
package com.greetings;
import org.astro.World;
public class Main{
public static void main(String[] args){
System.out.format("Greetings %s!%n", World.name());
}
}
src/com.greetings/module-info.java
module org.astro {
exports org.astro;
}
编译modules,一次编译一个module。使用javac命令编译module com.greetings 指定module的路径,它关联的module org.astro 和其他输出包的类型都会被关联到。
E:07_Learnjava9 eaxmple>javac -d modsorg.astro srcorg.astroorgastroWorld.java
E:07_Learnjava9 eaxmple>javac -d modsorg.astro srcorg.astromodule-info.java
E:07_Learnjava9 eaxmple>javac --module-path mods -d modscom.greetings srccom.greetingsmodule-in
fo.java
E:07_Learnjava9 eaxmple>javac --module-path mods -d modscom.greetings srccom.greetingscomgreet
ingsMain.java
E:07_Learnjava9 eaxmple>java --module-path mods -m com.greetings/com.greetings.Main
Greetings world!
在编译module org.astro的时候有一个要注意的地方。因为在module的声明里面有输出org.astro这个包,所以要先编译这个包下的内容,即先编译World.java,否则就会报如下错误。
E:07_Learnjava9 eaxmple>javac -d modsorg.astro srcorg.astromodule-info.java
srcorg.astromodule-info.java:2: 错误: 程序包为空或不存在: org.astro
exports org.astro;
^
1 个错误
最后的目录结构如下
├─mods
│ ├─com
│ │ └─greetings
│ │ │ module-info.class
│ │ │
│ │ └─com
│ │ └─greetings
│ │ Main.class
│ │
│ └─org.astro
│ │ module-info.class
│ │
│ └─org
│ └─astro
│ World.class
│
└─src
├─com.greetings
│ │ module-info.java
│ │
│ └─com
│ └─greetings
│ Main.java
│
└─org.astro
Multi-module compilation
在上一个例子中,我们将module com.greetings 和module org.astro分开编译的。
在linux中,可以使用如下命令:
$ mkdir mods
$ javac -d mods --module-source-path src $(find src -name "*.java")
$ find mods -type f
mods/com.greetings/com/greetings/Main.class
mods/com.greetings/module-info.class
mods/org.astro/module-info.class
mods/org.astro/org/astro/World.class
在windos中查找文件的命令为
E: 7_Learnjava9 eaxmple>for /r src %i in (*.java) do @echo %i
E: 7_Learnjava9 eaxmplesrccom.greetingsmodule-info.java
E: 7_Learnjava9 eaxmplesrccom.greetingscomgreetingsMain.java
E: 7_Learnjava9 eaxmplesrcorg.astromodule-info.java
E: 7_Learnjava9 eaxmplesrcorg.astroorgastroWorld.java
但是一次性编译多个模块没有成功。
Packaging
到现在,编译的module内容都是放在文件系统里面的。出于运输和部署的目的,将module打包成模块化的jar更便利。模块化的JAR是常规的jar文件,在它的顶级目录下有一个module-info.class文件。下面的例子生成了org.astro@1.0.jar和com.greetings.jar,放在mlib文件夹下。
E:07_Learnjava9 eaxmple>jar --create --file=mliborg.astro@1.0.jar --module-version=1.0 -C modsor
g.astro .
E:07_Learnjava9 eaxmple>jar --create --file=mlibcom.greetings.jar --main-class=com.greetings.Main
-C modscom.greetings .
E:07_Learnjava9 eaxmple>dir mlib
驱动器 E 中的卷是 文档
卷的序列号是 0005-F6CF
E:07_Learnjava9 eaxmplemlib 的目录
2018/03/08 周四 15:00 <DIR> .
2018/03/08 周四 15:00 <DIR> ..
2018/03/08 周四 15:00 1,357 com.greetings.jar
2018/03/08 周四 14:58 1,152 org.astro@1.0.jar
2 个文件 2,509 字节
2 个目录 248,652,009,472 可用字节
使用jar –help可以看到jar命令的使用方法。
在这个例子里面,module org.astro打包指明了它的版本是1.0。Module com.greetings也被打包并指明它的主类是com.greetings.Main。我们可以执行module com.greetings 而不需要指明主类。
E:07_Learnjava9 eaxmple>java -p mlib -m com.greetings
Greetings world!
这个命令行里面的-p也可以换成–module-path,都表示模块路径。
可以通过jar –help来看jar命令的其他选项,其中有一个是打印被打成jar包的module的模块声明。
E:07_Learnjava9 eaxmple>jar --describe-module --file=mliborg.astro@1.0.jar
org.astro@1.0 jar:file:///E:/07_Learn/java9%20eaxmple/mlib/org.astro@1.0.jar/!module-info.class
exports org.astro
requires java.base mandated
Missing requires or missing exports
我们把上个例子中com.greetings模块里面的requires注释掉,看看会发生什么。
srccom.greetingsmodule-info.java
module com.greetings{
// requires org.astro;
}
E:07_Learnjava9 eaxmple>javac -p mods -d modscom.greetings srccom.greetingsmodule-info.java src
com.greetingscomgreetingsMain.java
srccom.greetingscomgreetingsMain.java:2: 错误: 程序包 org.astro 不可见
import org.astro.World;
^
(程序包 org.astro 已在模块 org.astro 中声明, 但模块 com.greetings 未读取它)
1 个错误
我们现在再来把这个bug修复,但是将org.astro模块声明里面的exports去掉:
srccom.greetingsmodule-info.java
module com.greetings{
requires org.astro;
}
srcorg.astromodule-info.java
module org.astro{
// exports org.astro;
}
E:07_Learnjava9 eaxmple>javac -d modsorg.astro srcorg.astromodule-info.java srcorg.astroorga
stroWorld.java
E:07_Learnjava9 eaxmple>javac -p mods -d modscom.greetings srccom.greetingsmodule-info.java src
com.greetingscomgreetingsMain.java
srccom.greetingscomgreetingsMain.java:2: 错误: 程序包 org.astro 不可见
import org.astro.World;
^
(程序包 org.astro 已在模块 org.astro 中声明, 但该模块未导出它)
1 个错误
Services
服务允许服务使用者和服务提供者之间的松散耦合。
这个例子里面有一个服务消费者和一个服务提供者:
- module com.socket 提供了network sockets的API. 这个API在com.socket包里面,所以这个包是输出的。这个API是可插拔的,可以替代实现。这个服务类是同一个module里面的com.socket.spi.NetworkSocketProvider类。因此包com.socket.spi也是输出的。
- module org.fastsocket 是一个服务提供者模块。它提供了com.socket.spi.NetworkSocketProvider的实现。它并不输出任何包。
下面是com.socket的源码。
srccom.socketmodule-info.java
module com.socket{
exports com.socket;
exports com.socket.spi;
uses com.socket.spi.NetworkSocketProvider;
}
srccom.socketcomsocketspiNetworkSocketProvider.java
package com.socket.spi;
import com.socket.NetworkSocket;
public abstract class NetworkSocketProvider{
protected NetworkSocketProvider(){}
public abstract NetworkSocket openNetworkSocket();
}
srccom.socketcomsocketNetworkSocket.java
package com.socket;
import java.io.Closeable;
import java.util.Iterator;
import java.util.ServiceLoader;
import com.socket.spi.NetworkSocketProvider;
public abstract class NetworkSocket implements Closeable{
protected NetworkSocket(){}
public static NetworkSocket open(){
ServiceLoader<NetworkSocketProvider> sl = ServiceLoader.load(NetworkSocketProvider.class);
Iterator<NetworkSocketProvider> iter = sl.iterator();
if (!iter.hasNext()){
throw new RuntimeException("No service provider found!");
}
NetworkSocketProvider provider = iter.next();
return provider.openNetworkSocket();
}
}
下面是module org.fastsocket的源码。
srcorg.fastsocketmodule-info.java
module org.fastsocket {
requires com.socket;
proviides com.socket.spi.NetworkSocketProvider with org.fastsocket.FastNetworkSocketProvider;
}
srcorg.fastsocketorgfastsocketFastNetworkSocketProvider.java
package org.fastsocket;
import com.socket.NetworkSocket;
import com.socket.spi.NetworkSocketProvider;
public class FastNetworkSocketProvider extends NetworkSocketProvider {
public FastNetworkSocketProvider(){}
@Override
public NetworkSocket openNetworkSocket(){
return new FastNetworkSocket();
}
}
srcorg.fastsocketorgfastsocketFastNetworkSocket.java
package org.fastsocket;
import com.socket.NetworkSocket;
class FastNetworkSocket extends NetworkSocket{
FastNetworkSocket(){}
public void close(){}
}
然后将所有文件都编译
E: 7_Learnjava9 eaxmple>javac -d modscom.socket srccom.socketmodule-info.java srccom.socketco
msocketspiNetworkSocketProvider.java srccom.socketcomsocketNetworkSocket.java
E: 7_Learnjava9 eaxmple>javac --module-path mods -d modsorg.fastsocket srcorg.fastsocketorgfas
tsocketFastNetworkSocketProvider.java srcorg.fastsocketorgfastsocketFastNetworkSocket.java src
org.fastsocketmodule-info.java
最后再来修改com.greetings,让它来使用API.
srccom.greetinsmodule-info.java
module com.greetings{
requires com.socket;
}
srccom.greetingscomgreetinsMain.java
package com.greetings;
import com.socket.NetworkSocket;
public class Main{
public static void main(String[] args){
NetworkSocket s = NetworkSocket.open();
System.out.println(s.getClass());
}
}
编译
E:07_Learnjava9 eaxmple>javac -d modscom.greetings -p mods srccom.greetings*.java srccom.greet
ingscomgreetings*.java
最后来运行:
E:07_Learnjava9 eaxmple>java -p mods -m com.greetings/com.greetings.Main
class org.fastsocket.FastNetworkSocket
E:07_Learnjava9 eaxmple>
The linker
jlink 是一个链接器工具,它能用来链接模块集以及它们的传递依赖,还能自定义创建模块运行时映像(参见JEP 220)。
目前,这个工具要求被链接的模块是模块化的jar或JDOM格式的。JDK是以JDOM格式来构建包的。
下面的这个例子创建了一张运行时映像,包括com.greetings模块以及传递性的依赖:
E: 7_Learnjava9 eaxmple>jlink --module-path %JAVA_HOME%jmods;mlib --add-modules com.greetings --o
utput greetingsapp
E: 7_Learnjava9 eaxmple>
linux环境下要写成
jlink --module-path $JAVA_HOME/jmods:mlib --add-modules com.greetings --output greetingsapp
–module-path 打包了的模块的路径
%JAVA_HOME%jmods 是包含java.base.jmod,其他标准还有JDK模块的文件夹。
mlib文件夹包含com.greetings模块构建。
jlink工具支持许多高级选项来定制生成的映像,参见jlink –help获取更多选项。
–patch-module
以前开发者们修改类,例如java.util.concurrent类,会先从CVS检出,然后编译源码,最后使用-Xbootclasspath/p部署。
现在,-Xbootclasspath/p 已经被废弃了,它的模块被–patch-module代替了,用来覆盖模块中的类。它也可以用来想模块里面增加文件。javac命令也支持–patch-module选项。
下面是编译java.util.concurrent.ConcurrentHashMap的一个新版本并且在运行时使用它的例子
javac --patch-module java.base=src -d mypatches/java.base
src/java.base/java/util/concurrent/ConcurrentHashMap.java
java --patch-module java.base=mypatches/java.base ...
More information
- The State of the Module System
- JEP 261:Module System
- Project Jigsaw
最后
以上就是迷路树叶为你收集整理的Project Jigsaw:Module System Quick-Start GuideProject Jigsaw:Module System Quick-Start Guide的全部内容,希望文章能够帮你解决Project Jigsaw:Module System Quick-Start GuideProject Jigsaw:Module System Quick-Start Guide所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复