我是靠谱客的博主 迷路树叶,最近开发中收集的这篇文章主要介绍Project Jigsaw:Module System Quick-Start GuideProject Jigsaw:Module System Quick-Start Guide,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部