Java Platform Module System Quick-Start Guide

All source code is available at github.

Multiple Modules

Module org.astro

  • exports package org.astro
[yunpxu@yunpxu-mac JavaModule]$ tree org.astro
org.astro
├── org.astro.iml
└── src
    ├── module-info.java
    └── org
        └── astro
            └── World.java

module-info.java

[yunpxu@yunpxu-mac JavaModule]$ cat org.astro/src/module-info.java 
module org.astro {
    exports org.astro;
}

World.java

[yunpxu@yunpxu-mac JavaModule]$ cat org.astro/src/org/astro/World.java 
package org.astro;

public class World {
    public static String name() {
        return "world";
    }
}

Compile module

[yunpxu@yunpxu-mac JavaModule]$ mkdir -p out/production/org.astro
[yunpxu@yunpxu-mac JavaModule]$ javac -d out/production/org.astro/ org.astro/src/org/astro/World.java org.astro/src/module-info.java 
[yunpxu@yunpxu-mac JavaModule]$ tree out/production/org.astro/
out/production/org.astro/
├── module-info.class
└── org
    └── astro
        └── World.class

Module com.greetings

  • requires module org.astro

module-info.java

[yunpxu@yunpxu-mac JavaModule]$ cat com.greetings/src/module-info.java 
module com.greetings {
    requires org.astro;
}

Main.java

[yunpxu@yunpxu-mac JavaModule]$ cat com.greetings/src/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());
    }
}

Compile and run module

[yunpxu@yunpxu-mac JavaModule]$ javac --module-path out/production/ -d out/production/com.greetings/ com.greetings/src/com/greetings/Main.java com.greetings/src/module-info.java 
[yunpxu@yunpxu-mac JavaModule]$ java --module-path out/production/ -m com.greetings/com.greetings.Main
Greetings world!

Multi-module packaging

Multi-module compilation

[yunpxu@yunpxu-mac JavaModule]$ javac -d out/production/ --module-source-path './*/src' $(find org.astro/ -name '*.java') $(find com.greetings/ -name '*.java')
[yunpxu@yunpxu-mac JavaModule]$ tree out/production/com.greetings/
out/production/com.greetings/
├── com
│   └── greetings
│       └── Main.class
└── module-info.class
[yunpxu@yunpxu-mac JavaModule]$ tree out/production/org.astro/
out/production/org.astro/
├── module-info.class
└── org
    └── astro
        └── World.class

Pack module org.astro

[yunpxu@yunpxu-mac artifacts]$ cd out/artifacts
[yunpxu@yunpxu-mac artifacts]$ jar cvf org.astro.jar -C ../production/org.astro/ .
added manifest
added module-info: module-info.class
adding: org/(in = 0) (out= 0)(stored 0%)
adding: org/astro/(in = 0) (out= 0)(stored 0%)
adding: org/astro/World.class(in = 276) (out= 212)(deflated 23%)

Pack module com.greetings

The main class of module com.greetings is com.greetings.Main

[yunpxu@yunpxu-mac artifacts]$ jar cvfe com.greetings.jar com.greetings.Main -C /Users/yunpxu/IdeaProjects/JavaModule/out/production/com.greetings/ .
added manifest
added module-info: module-info.class
adding: com/(in = 0) (out= 0)(stored 0%)
adding: com/greetings/(in = 0) (out= 0)(stored 0%)
adding: com/greetings/Main.class(in = 541) (out= 348)(deflated 35%)

Run module com.greetings

[yunpxu@yunpxu-mac artifacts]$ java --module-path . -m com.greetings
Greetings world!

Services

Module com.service

Module com.service defines a service EchoService, and also uses this service(through ServiceLoader).

[yunpxu@yunpxu-mac JavaModule]$ tree com.service
com.service
├── com.service.iml
└── src
    ├── com
    │   └── service
    │       └── EchoService.java
    └── module-info.java

EchoService interface

[yunpxu@yunpxu-mac JavaModule]$ cat com.service/src/com/service/EchoService.java 
package com.service;

import java.util.ServiceLoader;
import java.util.stream.Stream;

public interface EchoService {
    void echo(String message);

    /**
     * Load first service provider, if no service provider found throw RuntimeException.
     *
     * @return
     */
    static EchoService getServiceProvider() {
        return ServiceLoader.load(EchoService.class).findFirst().orElseThrow(() -> new RuntimeException("Service Unavailable"));
    }

    /**
     * Load all service providers.
     *
     * @return
     */
    static Stream<EchoService> getServiceProviders() {
        return ServiceLoader.load(EchoService.class).stream().map(ServiceLoader.Provider::get);
    }
}

module-info

[yunpxu@yunpxu-mac JavaModule]$ cat com.service/src/module-info.java 
module com.service {
    exports com.service;
    uses com.service.EchoService;
}

Module com.service.impl

Module com.service.impl provides two implementations for service EchoService.

[yunpxu@yunpxu-mac JavaModule]$ tree com.service.impl
com.service.impl
├── com.service.impl.iml
└── src
    ├── com
    │   └── service
    │       └── impl
    │           ├── EchoGreetingServiceImpl.java
    │           └── EchoServiceImpl.java
    └── module-info.java

EchoServiceImpl

[yunpxu@yunpxu-mac JavaModule]$ cat com.service.impl/src/com/service/impl/EchoServiceImpl.java 
package com.service.impl;

import com.service.EchoService;

public class EchoServiceImpl implements EchoService {
    @Override
    public void echo(String message) {
        System.out.println(message);
    }
}

EchoGreetingServiceImpl

[yunpxu@yunpxu-mac JavaModule]$ cat com.service.impl/src/com/service/impl/EchoGreetingServiceImpl.java
package com.service.impl;

import com.service.EchoService;

public class EchoGreetingServiceImpl implements EchoService {
    @Override
    public void echo(String message) {
        System.out.println("Greeting " + message);
    }
}

module-info

[yunpxu@yunpxu-mac JavaModule]$ cat com.service.impl/src/module-info.java 
module com.service.impl {
    requires com.service;
    provides com.service.EchoService with com.service.impl.EchoServiceImpl,
            com.service.impl.EchoGreetingServiceImpl;
}

Module com.service.client

Module com.service.client consumes service EchoService.

[yunpxu@yunpxu-mac JavaModule]$ tree com.service.client
com.service.client
├── com.service.client.iml
└── src
    ├── com
    │   └── service
    │       └── client
    │           └── Client.java
    └── module-info.java

Client

[yunpxu@yunpxu-mac JavaModule]$ cat com.service.client/src/com/service/client/Client.java 
package com.service.client;

import com.service.EchoService;

import java.util.stream.Stream;

public class Client {
    public static void main(String[] args) {
        EchoService echoService = EchoService.getServiceProvider();
        echoService.echo("1");

        Stream<EchoService> echoServices = EchoService.getServiceProviders();
        echoServices.forEach(e -> e.echo("2"));
    }
}

module-info

[yunpxu@yunpxu-mac JavaModule]$ cat com.service.client/src/module-info.java 
module com.service.client {
    requires com.service;
}

Compile Services

Compile module com.service, com.service.impl and com.service.client

[yunpxu@yunpxu-mac JavaModule]$ javac -d out/production/ --module-source-path './*/src' $(find com.service* -name '*.java')

Run Client

Run module com.service.client

[yunpxu@yunpxu-mac JavaModule]$ java --module-path out/production/ -m com.service.client/com.service.client.Client
1
2
Greeting 2

The Linker

You can use the jlink tool to assemble and optimize a set of modules and their dependencies into a custom runtime image.

Create Runtime Image

Create a runtime image with module com.service.client and com.service.impl and their dependencies(com.service and java.base).

[yunpxu@yunpxu-mac JavaModule]$ jlink --module-path out/production/ --add-modules com.service.client,com.service.impl --output out/artifacts/EchoApp

Runtime Image Hierarchy

[yunpxu@yunpxu-mac JavaModule]$ tree out/artifacts/EchoApp/
out/artifacts/EchoApp/
├── bin
│   ├── java
│   └── keytool
├── conf
│   ├── net.properties
│   └── security
│       ├── java.policy
│       ├── java.security
│       └── policy
│           ├── README.txt
│           ├── limited
│           │   ├── default_US_export.policy
│           │   ├── default_local.policy
│           │   └── exempt_local.policy
│           └── unlimited
│               ├── default_US_export.policy
│               └── default_local.policy
├── include
│   ├── classfile_constants.h
│   ├── darwin
│   │   └── jni_md.h
│   ├── jni.h
│   ├── jvmti.h
│   └── jvmticmlr.h
├── legal
│   └── java.base
│       ├── ADDITIONAL_LICENSE_INFO
│       ├── ASSEMBLY_EXCEPTION
│       ├── LICENSE
│       ├── aes.md
│       ├── asm.md
│       ├── c-libutl.md
│       ├── cldr.md
│       ├── icu.md
│       ├── public_suffix.md
│       └── unicode.md
├── lib
│   ├── classlist
│   ├── jli
│   │   └── libjli.dylib
│   ├── jrt-fs.jar
│   ├── jspawnhelper
│   ├── jvm.cfg
│   ├── libjava.dylib
│   ├── libjimage.dylib
│   ├── libjsig.dylib
│   ├── libnet.dylib
│   ├── libnio.dylib
│   ├── libosxsecurity.dylib
│   ├── libverify.dylib
│   ├── libzip.dylib
│   ├── modules
│   ├── security
│   │   ├── blacklisted.certs
│   │   ├── cacerts
│   │   ├── default.policy
│   │   └── public_suffix_list.dat
│   ├── server
│   │   ├── Xusage.txt
│   │   ├── libjsig.dylib
│   │   └── libjvm.dylib
│   └── tzdb.dat
└── release

Run Image

EchoApp is now a standalone app and can be ran on machines without java installed.

[yunpxu@yunpxu-mac JavaModule]$ ./out/artifacts/EchoApp/bin/java --list-modules
com.service
com.service.client
com.service.impl
java.base@11.0.1

[yunpxu@yunpxu-mac JavaModule]$ ./out/artifacts/EchoApp/bin/java --module com.service.client/com.service.client.Client
1
2
Greeting 2

References

Project Jigsaw: Module System Quick-Start Guide

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容