A note from studying Java 9 Project Jigsaw.
OS Windows 10
Java
>java --version
java 9
Java(TM) SE Runtime Environment (build 9+181)
Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode)
Hello World
|-main/
| |-class/
| `-src/
| |-module-info.java
| `-sample/main/
| `-Main.java
|
`-sub/
|-class/
`-src/
|-module-info.java
`-sample/sub/
|-api/
| `-Foo.java
|-internal/
| `-FooImpl.java
|
`-FooFactory.java
sub/src/sample/sub/api/Foo.java
package sample.sub.api;
public interface Foo {
void hello();
}
sub/src/sample/sub/internal/FooImpl.java
package sample.sub.internal;
import sample.sub.api.Foo;
public class FooImpl implements Foo {
@Override
public void hello() {
System.out.println("FooImpl.hello()");
}
}
sub/src/sample/sub/FooFactory.java
package sample.sub;
import sample.sub.api.Foo;
import sample.sub.internal.FooImpl;
public class FooFactory {
public static Foo newInstance() {
return new FooImpl();
}
}
sub/src/module-info.java
module sample_module.sub {
exports sample.sub;
exports sample.sub.api;
}
main/src/sample/main/Main.java
package sample.main;
import sample.sub.FooFactory;
import sample.sub.api.Foo;
public class Main {
public static void main(String... args) {
Foo foo = FooFactory.newInstance();
foo.hello();
}
}
main/src/module-info.java
module sample_module.main {
requires sample_module.sub;
}
#Compile the sub module
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\FooFactory.java sub\src\sample\sub\api\Foo.java sub\src\sample\sub\internal\FooImpl.java
#Compile the main module
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java
> java -p main\class;sub\class -m sample_module.main/sample.main.Main
FooImpl.hello()
sub/src/module-info.java
module sample_module.sub {
exports sample.sub;
exports sample.sub.api;
}
--The module declaration is written in a special file called module-info.java
placed in the root package.
--Name is fixed to module-info.java
--Module declaration is described in the format module <module name> {<module definition>}
--Module names can be separated by dots .
, just like package names.
--Usually, it seems that the name is the same as the package name, but in that case it is difficult to distinguish between the package name and the module name in the sample implementation, so here I dare to name sample_module.sub
different from the package. Attached
--You can write a definition for this module in {}
--ʻExportsspecifies packages to be exposed to the outside --Here, two packages,
sample.sub and
sample.sub.api, are open to the outside. --
sample.sub.internal` is intended as an internal API, so I try not to publish it.
main/src/module-info.java
module sample_module.main {
requires sample_module.sub;
}
--The side that refers to other modules also describes the module declaration using module-info.java
as well as the side that is referenced.
--requries
defines the modules this module depends on
--Here, it is defined to refer to the sample_module.sub
module mentioned earlier.
--I saw the explanation that you can't start the package (sample.main
) with the main class without ʻexports, but when I actually tried it, it worked even if I didn't ʻexports
.
--Did the specifications change on the way?
#Compile sub module
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\FooFactory.java sub\src\sample\sub\api\Foo.java sub\src\sample\sub\internal\FooImpl.java
#Compile main module
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java
--Compile still uses the javac
command
--If there is no dependent module, you can compile with the conventional specifications (compilation of sub module)
--Don't forget to include module-info.java
in the source to be compiled!
--If there are dependent modules, specify the path of the folder where the dependent modules are located with the -p
(or --module-path
) option.
--In older articles, this option was introduced in -mp
, but it seems that it has changed.
> java -p main\class;sub\class -m sample_module.main/sample.main.Main
--Also at startup, specify the location of the module to use with the -p
(--module-path
) option
--If there are multiple paths, specify them by concatenating them with a semicolon ;
for Windows and a colon :
for Linux.
--Also, the specification of the main class has been changed to specify with the -m
(--module
) option (when using a module).
--The specification of the main class name has also changed, and specify <module name> / <main class name>
--Here, sample_module.main / sample.main.Main
is used to specify the sample.main.Main
class of the sample_module.main
module.
Main.java
package sample.main;
import sample.sub.FooFactory;
import sample.sub.api.Foo;
import sample.sub.internal.FooImpl;
public class Main {
public static void main(String... args) {
FooImpl foo = (FooImpl)FooFactory.newInstance();
foo.hello();
}
}
Compile error
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java
main\src\sample\main\Main.java:5:error:Package sample.sub.internal cannot be displayed
import sample.sub.internal.FooImpl;
^
(Package sample.sub.internal is the module sample_module.Declared in sub but not exported)
1 error
Like this, you can't refer to packages that aren't ʻexports`.
Try using the Hello World program by packaging both main and sub in a jar.
Same up to compiling with javac
.
#Create jar for sub module
> jar -c -f sub\jar\sub-module.jar -C sub\class .
#Create jar for main module
> jar -c -f main\jar\main-module.jar -C main\class .
--Use the jar
command as before to create the module jar file
-- -c
is a command that means create a jar (short for --create
)
--Specify the output destination with -f <jar output destination path>
-- -C <directory to package> .
to package the specified directory into a jar
#Output sub module information
> jar -d -f sub\jar\sub-module.jar
sample_module.sub jar:file:///.../sub/jar/sub-module.jar/!module-info.class
exports sample.sub
exports sample.sub.api
requires java.base mandated
contains sample.sub.internal
#Output main module information
> jar -d -f main\jar\main-module.jar
sample_module.main jar:file:///.../main/jar/main-module.jar/!module-info.class
requires java.base mandated
requires sample_module.sub
contains sample.main
-- -d
(--describe-module
) can output the module information of jar.
--ʻExports is a public package --
requires is a dependent module --
java.base is a module that includes the
java.lang package, and it always comes with it even if you do not specify it. --
contains` is probably a private package
> java -p sub\jar;main\jar -m sample_module.main/sample.main.Main
FooImpl.hello()
--If you specify the folder with the module ( jar
) with -p
, it seems that the jar there will be read.
--You may directly enter the path to the jar file
There are three main types of modules.
named module
Module with definition information (module-info.class
) read by module path (--module-path
).
When we talk about modules, we often refer to them.
automatic module A jar with no definition information read in the module path.
All packages are treated as ʻexports`. Also, the module name is automatically completed from the jar file name.
This is the case if you specify a jar file created before Java 9 with --module-path
.
I haven't found a clear definition, but it seems that it should be a jar file because the module name is completed from the file name. Javadoc also has the following description, so I feel that it needs to be a jar at a minimum.
A JAR file that does not have a module-info.class in its top-level directory defines an automatic module (Translation) Jar files that do not have
module-info.class
at the top level define an automatic module
http://download.java.net/java/jigsaw/docs/api/java/lang/module/ModuleFinder.html#of-java.nio.file.Path...-
unnamed module
Modules loaded with the classpath (--class-path
).
All packages are treated as ʻexports`.
Try various combinations of each module (named module, automatic module, unnamed module).
If you tabulate the results first,
It looks like this.
sub/src/sample/sub/Sub.java
package sample.sub;
public class Sub {
public void method() {
System.out.println("Sub.method()");
}
}
main/src/sample/main/Main.java
package sample.main;
import sample.sub.Sub;
public class Main {
public static void main(String... args) {
Sub sub = new Sub();
sub.method();
}
}
named module -> named module Hello World is this, so I will omit it.
named module -> automatic module
Folder structure
|-main/
| |-class/
| `-src/
| |-module-info.java
| `-sample/main/
| `-Main.java
|
`-sub/
|-class/
`-src/
`-sample/sub/
`-Sub.java
Compile sub module
#compile
> javac -d sub\class sub\src\sample\sub\Sub.java
#jar creation
> jar -c -f sub\jar\no_module-sub.jar -C sub\class .
main\src\module-info.java
module sample_module.main {
requires no.module.sub;
}
--The name of the sub module specified in requires
specifies the name that is completed from the jar file name.
--In the case of no_module-sub.jar
, the module name will be no.module.sub
--Detailed conversion rules will be described later
Compile and launch the main module
#Compile main module
> javac -p sub\jar\no_module-sub.jar -d main\class main\src\module-info.java main\src\sample\main\Main.java
#Start-up
> java -p sub\jar\no_module-sub.jar;main\class -m sample_module.main/sample.main.Main
Sub.method()
--Set the sub module to -p
(--module-path
) and start it
.jar
--Extract only before the regular expression -(\ d + (\. | $))
--The part after this regular expression is treated as a version string
--xxx-1.1.2.jar
extracts xxx
as the module name
--Replace characters other than alphanumeric characters ([^ A-Za-z0-9]
) with dots (.
)
--If the dot (.
) is repeated, replace it with one dot.named module -> unnamed module I can't seem to do it.
main/src/module-info.java
module sample_module.main {
// requires no.module.sub;
}
> javac -cp sub\jar\no_module-sub.jar -d main\class main\src\module-info.java main\src\sample\main\Main.java
main\src\sample\main\Main.java:3:error:Package sample.sub does not exist
import sample.sub.Sub;
^
main\src\sample\main\Main.java:7:error:Can't find symbol
Sub sub = new Sub();
^
symbol:Class Sub
place:Class Main
main\src\sample\main\Main.java:7:error:Can't find symbol
Sub sub = new Sub();
^
symbol:Class Sub
place:Class Main
3 errors
Even if I set jar in the classpath (-cp
), the class cannot be read.
automatic module -> named module
Folder structure
|-main/
| |-class/
| `-src/
| `-sample/main/
| `-Main.java
|
`-sub/
|-class/
`-src/
|-module-info.java
`-sample/sub/
`-Sub.java
sub/src/module-info.java
module sample_module.sub {
exports sample.sub;
}
Compile sub module
#compile
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java
#jar creation
> jar -c -f sub\jar\module-sub.jar -C sub\class .
Compile main module
#compile
> javac -d main\class --add-modules sample_module.sub -p sub\jar\module-sub.jar main\src\sample\main\Main.java
#jar creation
> jar -c -f main\jar\no_module-main.jar -C main\class .
Run
> java -p sub\jar\module-sub.jar;main\jar\no_module-main.jar --add-modules sample_module.sub -m no.module.main/sample.main.Main
Sub.method()
--The main module works as an automatic module because it is specified in -p
(--module-path
) without module-info.java
.
--But because there is no module-info.java
, sample_module.sub
is not requires
and is in an unloaded state, maybe (expressed as not present on the module graph). Should I do it?)
--You can use --add-modules
to add any module to what is called a root module.
--I don't know exactly what the root module is, but I think it's probably adding a module as the starting point for the dependency graph.
--This will load the sample_module.sub
module and allow you to use the classes there.
--It seems that the automatic module is treated as if all other modules are requires
, so it seems that the module added as the root module can be referenced from the automatic module.
--In other words, it seems that you can refer to the sub module added to the root module with --add-modules
from the main module (automatic module).
This is an imagination looking at Togetter of the Gods, so it may or may not be different.
automatic module -> automatic module
Folder structure
|-main/
| |-class/
| `-src/
| `-sample/main/
| `-Main.java
|
`-sub/
|-class/
`-src/
`-sample/sub/
`-Sub.java
Compile sub module
#compile
> javac -d sub\class sub\src\sample\sub\Sub.java
#jar creation
> jar -c -f sub\jar\no_module-sub.jar -C sub\class .
Compile main module
#compile
> javac -d main\class -p sub\jar\no_module-sub.jar --add-modules no.module.sub main\src\sample\main\Main.java
# jar
> jar -c -f main\jar\no_module-main.jar -C main\class .
Start-up
> java -p sub\jar\no_module-sub.jar;main\jar\no_module-main.jar --add-modules no.module.sub -m no.module.main/sample.main.Main
Sub.method()
--This can also be executed by specifying --add-modules
.
--Since the main module is loaded as the main class, does it need to be specified in --add-modules
?
automatic module -> unnamed module
Compile sub module
#compile
> javac -d sub\class sub\src\sample\sub\Sub.java
#jar creation
> jar -c -f sub\jar\no_module-sub.jar -C sub\class .
Compile main module
#compile
> javac -d main\class -cp sub\jar\no_module-sub.jar main\src\sample\main\Main.java
# jar
> jar -c -f main\jar\no_module-main.jar -C main\class .
Run
> java -p main\jar\no_module-main.jar -cp sub\jar\no_module-sub.jar -m no.module.main/sample.main.Main
Sub.method()
--Can be treated as an unnamed module by setting the non-module jar in the classpath with -cp
unnamed module -> named module
Folder structure
|-main/
| |-class/
| `-src/
| `-sample/main/
| `-Main.java
|
`-sub/
|-class/
`-src/
|-module-info.java
`-sample/sub/
`-Sub.java
sub/src/module-info.java
module sample_module.sub {
exports sample.sub;
}
Compile sub module
#compile
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java
# jar
> jar -c -f sub\jar\module-sub.jar -C sub\class .
Compile main module
#compile
> javac -p sub\jar\module-sub.jar --add-modules sample_module.sub -d main\class main\src\sample\main\Main.java
#jar creation
> jar -c -f main\jar\no_module-main.jar -C main\class .
Run
> java -p sub\jar\module-sub.jar -cp main\jar\no_module-main.jar --add-modules sample_module.sub sample.main.Main
Sub.method()
--sub If you specify the module name with --add-modules
, it works.
--Since the main side is an unnamed module, the main class specification is the old way without -m
.
unnamed module -> automatic module
Folder structure
|-main/
| |-class/
| `-src/
| `-sample/main/
| `-Main.java
|
`-sub/
|-class/
`-src/
`-sample/sub/
`-Sub.java
Compile sub module
#compile
> javac -d sub\class sub\src\sample\sub\Sub.java
#jar creation
> jar -c -f sub\jar\no_module-sub.jar -C sub\class .
Compile main module
#compile
> javac -p sub\jar\no_module-sub.jar -d main\class --add-modules no.module.sub main\src\sample\main\Main.java
#jar creation
> jar -c -f main\jar\no_module-main.jar -C main\class .
Run
> java -p sub\jar\no_module-sub.jar -cp main\jar\no_module-main.jar --add-modules no.module.sub sample.main.Main
Sub.method()
--It works if you specify the module name that is completed from the file name with --add-modules
.
unnamed module -> unnamed module
Compile sub module
#compile
> javac -d sub\class sub\src\sample\sub\Sub.java
#jar creation
> jar -c -f sub\jar\no_module-sub.jar -C sub\class .
Compile main module
#compile
> javac -d main\class -cp sub\jar\no_module-sub.jar main\src\sample\main\Main.java
#jar creation
> jar -c -f main\jar\no_module-main.jar -C main\class .
Run
> java -cp sub\jar\no_module-sub.jar;main\jar\no_module-main.jar sample.main.Main
Sub.method()
--This is basically a module-free method, which is the same as compiling and running normally in Java 8 and below.
One of the following two modifiers can be set in requires
.
transitive
static
transitive
Module dependencies
A -> B -> C
Suppose a module B
depends on C
.
It is this transitive
qualifier that allows C
to automatically make requires
when another module ʻA loads
Bwith
requires`.
Folder structure
|-A/
| `-src/
| |-module-info.java
| `-a/
| `-A.java
|-B/
| `-src/
| |-module-info.java
| `-b/
| `-B.java
`-C/
`-src/
|-module-info.java
`-c/
`-C.java
** C module **
C.java
package c;
public class C {}
C/src/module-info.java
module module_c {
exports c;
}
** B module **
B.java
package b;
import c.C;
public class B {}
B/src/module-info.java
module module_b {
requires module_c;
exports b;
}
** A module **
A.java
package a;
import b.B;
import c.C;
public class A {}
A/src/module-info.java
module module_a {
requires module_b;
// requires module_c;Try without requiring C module
exports a;
}
compile
#Compiling C module
> javac -d c\class C\src\module-info.java C\src\c\C.java
#Compiling B module
> javac -p c\class -d b\class B\src\module-info.java B\src\b\B.java
#Compiling A module
> javac -p c\class;b\class -d a\class A\src\module-info.java A\src\a\A.java
A\src\a\A.java:4:error:Package c cannot be displayed
import c.C;
^
(Package c is module module_Declared in c, but module module_Not loaded in a)
1 error
The A module does not explicitly requires
the C module, so the package c
cannot be referenced.
B\src\module-info.java
module module_b {
requires transitive module_c;
exports b;
}
--Added transitive
to C module which was required
in module-info.java
of B module
#Compiling B module
> javac -p c\class -d b\class B\src\module-info.java B\src\b\B.java
#Compiling A module
> javac -p c\class;b\class -d a\class A\src\module-info.java A\src\a\A.java
--This time I was able to compile without error
static
Use static
for modules that are" required at compile time but optional at runtime ".
Folder structure
|-main/
| `-src/
| |-module-info.java
| `-sample/main/
| |-SubFactory.java
| `-Main.java
`-sub/
`-src/
|-module-info.java
`-sample/sub/
`-Sub.java
Sub.java
package sample.sub;
public class Sub {}
sub\src\module-info.java
module sample_module.sub {
exports sample.sub;
}
SubFactory.java
package sample.main;
import sample.sub.Sub;
public class SubFactory {
public static Sub newSub() {
return new Sub();
}
}
Main.java
package sample.main;
public class Main {
public static void main(String... args) {
System.out.println("Hello World!!");
}
}
main/src/module-info.java
module sample_module.main {
requires sample_module.sub;
}
--The main module has a class called SubFactory
that references the class of the sub module
--For this reason, the sub module is required at compile time.
--However, since the Main
class does not use SubFactory
, the sub module is not needed at startup.
Try compiling.
compile
#Compile sub module
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java
#Compile main module
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java main\src\sample\main\SubFactory.java
The compilation passes. Then try running it.
> java -p main\class -m sample_module.main/sample.main.Main
Error occurred during initialization of boot layer
java.lang.module.FindException: Module sample_module.sub not found, required by sample_module.main
An error occurred because the sub module could not be found.
main\src\module-info.java
module sample_module.main {
requires static sample_module.sub;
}
Compile and execute in the same way with static
.
#Compile main module
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java main\src\sample\main\SubFactory.java
#Run
> java -p main\class -m sample_module.main/sample.main.Main
Hello World!!
I was able to execute it.
open It cannot be referenced at compile time, but it can be controlled so that it can be referenced at runtime. This will be used when you are referencing the code using reflection.
There are two types, ʻopens, which is set for each package, and ʻopen module
, which is set for the entire module.
opens
Folder structure
|-main/
| `-src/
| |-module-info.java
| `-sample/main/
| `-Main.java
`-sub/
`-src/
|-module-info.java
`-sample/sub/
`-Sub.java
Sub.java
package sample.sub;
public class Sub {
public void sub() {
System.out.println("Sub.sub()");
}
}
sub\src\module-info.java
module sample_module.sub {
//First, create it without publishing it at all
}
Main.java
package sample.main;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Main {
public static void main(String... args) throws Exception {
Class<?> subClass = Class.forName("sample.sub.Sub");
Constructor<?> constructor = subClass.getConstructor();
Object sub = constructor.newInstance();
Method method = subClass.getMethod("sub");
method.invoke(sub);
}
}
The sample.sub
package is not directly referenced, and theSub.sub ()
method is executed using reflection.
main/src/module-info.java
module sample_module.main {
requires sample_module.sub;
}
Try compiling.
#Compile sub module
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java
#Compile main module
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java
sample.sub
is not statically referenced, so it compiles.
But when you do this.
> java -p sub\class;main\class -m sample_module.main/sample.main.Main
Exception in thread "main" java.lang.IllegalAccessException: class sample.main.Main (in module sample_module.main) cannot access class sample.sub.Sub (in module sample_module.sub) because module sample_module.sub does not export sample.sub to module sample_module.main
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:589)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:479)
at sample_module.main/sample.main.Main.main(Main.java:10)
ʻIllegalAccessException` is thrown.
Publish sample.sub
with ʻopens` and try again.
sub\src\module-info.java
module sample_module.sub {
opens sample.sub;
}
Compile and run
#Compile sub module
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java
#Compile main module
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java
#Run
> java -p sub\class;main\class -m sample_module.main/sample.main.Main
Sub.sub()
This time it worked fine.
By the way, if you refer to the sample.sub
package in Main.java
in this state (ʻopens sample.sub; `), it will be as follows.
Main.java
package sample.main;
import sample.sub.Sub;
public class Main {
public static void main(String... args) throws Exception {
new Sub().sub();
}
}
Normally, Sub
is new
to execute the method.
compile
#Compile main module
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java
main\src\sample\main\Main.java:3:error:Package sample.sub cannot be displayed
import sample.sub.Sub;
^
(Package sample.sub is the module sample_module.Declared in sub but not exported)
1 error
The sample.sub
package is just ʻopens, not ʻexports
.
Therefore, if you try to refer to it statically at compile time, an error will occur.
To summarize the availability of reference at each timing,
Reference timing | opens |
exports |
---|---|---|
At compile time | × | ○ |
runtime | ○ | ○ |
Like this.
open module
ʻOpens is a setting for a specific package, but if you specify ʻopen module
, ʻopens` is applied to the entire module.
Folder structure
|-main/
| `-src/
| |-module-info.java
| `-sample/main/
| `-Main.java
`-sub/
`-src/
|-module-info.java
`-sample/sub/
|-foo/
| `-Foo.java
`-Sub.java
Foo.java
package sample.sub.foo;
public class Foo {
public void foo() {
System.out.println("Foo.foo()");
}
}
sub/src/module-info.java
open module sample_module.sub {
exports sample.sub;
}
--Adding ʻopenbefore the module --Only
sample.sub ʻexports
, and nothing is set for the sample.sub.foo
package.
--Sub.java
has not changed
Main.java
package sample.main;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import sample.sub.Sub;
public class Main {
public static void main(String... args) throws Exception {
new Sub().sub();
Class<?> clazz = Class.forName("sample.sub.foo.Foo");
Constructor<?> constructor = clazz.getConstructor();
Object obj = constructor.newInstance();
Method method = clazz.getMethod("foo");
method.invoke(obj);
}
}
--The Sub
class is statically referenced to execute the method
--The Foo
class uses reflection to execute methods
Compile and run
#Compile sub module
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java sub\src\sample\sub\foo\Foo.java
#Compile main module
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java
#Run
> java -p sub\class;main\class -m sample_module.main/sample.main.Main
Sub.sub()
Foo.foo()
--sample.sub.foo.Foo
did not declare ʻopens or ʻexports
, but it can be referenced from reflection.
--By qualifying module
with ʻopen, all the packages contained in that module will be qualified with ʻopens
.
use, provides
ServiceLoader can be defined in module-info.java
from Java 9.
Folder structure
|-user/
| `-src/
| |-module-info.java
| `-sample/user/
| `-Main.java
|
`-provider/
`-src/
|-module-info.java
`-sample/provider/
|-api/
| `-Foo.java
`-impl/
`-FooImpl.java
Foo.java
package sample.provider.api;
public interface Foo {
void foo();
}
FooImpl.java
package sample.provider.impl;
import sample.provider.api.Foo;
public class FooImpl implements Foo {
@Override
public void foo() {
System.out.println("FooImpl.foo()");
}
}
provider/src/module-info.java
module sample_module.provider {
exports sample.provider.api;
provides sample.provider.api.Foo with sample.provider.impl.FooImpl;
}
Main.java
package sample.user;
import java.util.ServiceLoader;
import sample.provider.api.Foo;
public class Main {
public static void main(String... args) {
for (Foo foo : ServiceLoader.load(Foo.class)) {
foo.foo();
}
}
}
user/src/module-info.java
module sample_module.user {
requires sample_module.provider;
uses sample.provider.api.Foo;
}
compile
#Compiling provider module
> javac -d provider\class provider\src\module-info.java provider\src\sample\provider\api\Foo.java provider\src\sample\provider\impl\FooImpl.java
#Compile user module
> javac -d user\class -p provider\class user\src\module-info.java user\src\sample\user\Main.java
Run
> java -p provider\class;user\class -m sample_module.user/sample.user.Main
FooImpl.foo()
provider/src/module-info.java
module sample_module.provider {
exports sample.provider.api;
provides sample.provider.api.Foo with sample.provider.impl.FooImpl;
}
user/src/module-info.java
module sample_module.user {
requires sample_module.provider;
uses sample.provider.api.Foo;
}
--The provider of "service provider [^ 1]" uses provides
to specify the" service provider "for" service [^ 2] ".
--provides <service> with <service provider>;
--If you have multiple "service providers", you can list the "service providers" after with
separated by commas.
--The side that uses ServiceLoader
uses ʻusesto specify the" service "to use. --ʻUses <service>;
--The rest is used in the same way as the normal ServiceLoader
It seems that you should be aware that there are more declaration methods, such as when reading the code of the OSS framework.
[^ 1]: Class that implements "service" [^ 2]: Interfaces, abstract classes, etc.
jlink You can use the jlink command to create a Java runtime (subset) that contains only the bare minimum of modules. Even if JRE is not installed in the distribution destination, you can start the application by including the subset created by jlink.
Folder structure
`-src/
|-module-info.java
`-sample/jlink/
`-Main.java
Main.java
package sample.jlink;
public class Main {
public static void main(String... args) {
System.out.println("Hello jlink!!");
}
}
module-info.java
module sample_module.jlink {
}
#compile
> javac -d class src\module-info.java src\sample\jlink\Main.java
#jar creation
> jar -c -f jar\module-jlink.jar -C class .
#Create runtime with jlink
> jlink -p .\jar;%JAVA_HOME%\jmods --add-modules sample_module.jlink --output .\output
--In the jlink
command, specify at least the following
- -p
(--module-path
)
--Specify the path where the module to be included exists
--The standard library modules are also required, so add the jmods
folder under the JDK9 installation folder (% JAVA_HOME%
) to the module path as well.
- --add-modules
--It seems to specify the root module
--I'm not sure what the root module is, but I think it's probably the starting point for building a graph of module dependencies.
――If you specify here, I think that the modules required for the Imozuru expression will be searched and incorporated into the runtime to be created.
- --output
--Specify the path of the output destination folder
--If the folder already exists, an error will occur, so specify a path that does not exist.
The application with runtime is output under the ʻoutput` folder as shown below.
`-output/
|-bin/
|-conf/
|-include/
|-legal/
|-lib/
`-release
Under bin
is the java.exe
file, which is the java
command for the subset.
#Go to the subset bin
> cd output\bin
#Check the included modules
> java --list-modules
java.base@9
sample_module.jlink
The subset contains only the minimum required modules (java.base
and sample_module.jlink
).
Try starting the program.
> java -m sample_module.jlink/sample.jlink.Main
Hello jlink!!
sample_module.jlink
is built into the runtime, so you don't need to specify it with -p
.
By the way, the size of the created runtime was 35.9 MB when I checked it with Windows Explorer.
Can be compressed to some extent as an option.
> jlink --compress=2 -p .\jar;%JAVA_HOME%\jmods --add-modules sample_module.jlink --output .\output
--Compression can be specified with --compress = N
.
--You can specify one of 0
, 1
, and 2
for N
.
--The help explains: (I'm not sure about Level 1)
-c, --compress=<0|1|2> Enable compression of resources:
Level 0: No compression
Level 1: Constant string sharing
Level 2: ZIP
--By the way, the size is now 24.2 MB
The need to specify the main class with -m
at startup is not very good considering when distributing to people who are not familiar with Java.
In that case, it is convenient to generate a script file for startup.
> jlink --launcher jlink-hello=sample_module.jlink/sample.jlink.Main -p .\jar;%JAVA_HOME%\jmods --add-modules sample_module.jlink --output .\output
--Specify --launcher <command name> = <main class>
--The start script specified by <command name>
is output under ʻoutput \ bin`, so if you execute it, the program will start.
#Go under bin
> cd output\bin
#Run startup script
> jlink-hello.bat
Hello jlink!!
The generated script file has the following contents.
jlink-hello.bat
@echo off
set JLINK_VM_OPTIONS=
set DIR=%~dp0
"%DIR%\java" %JLINK_VM_OPTIONS% -m sample_module.jlink/sample.jlink.Main %*
A shell script for Linux was also output, but can it be started?
You can use the jdeps
command to find out which module the jar file depends on.
When you add an existing non-module jar, you will know which module in the standard library to add.
As a test, check out Apache Commons lang-3.
> jdeps -s commons-lang3-3.6.jar
commons-lang3-3.6.jar -> java.base
commons-lang3-3.6.jar -> java.desktop
Feeding the jar with the -s
option will show you the dependent modules.
java.desktop is a module that includes awt and swing, but there are beans and so on. I see.
If the jar is a named module, you need to specify the dependent module with --module-path
(well, of course, it feels weird to have a dependent module to look up the dependent module. To do).
-Latest Java Information Bureau-Create a module with Project Jigsaw ahead of Java SE 9: ITpro -Latest Java Information Bureau --Java SE 9, Project Jigsaw standard module and dependency description: ITpro -Latest Java Information Bureau --Customization of JRE by Project Jigsaw: ITpro
Recommended Posts