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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容