The official document: docs.oracle.com/javase/9/in…

About java9 new features, the original official: docs.oracle.com/javase/9/wh…

This thing is a list, the exact technical details need to be dug up according to the official documentation.

Modular – system of modules

The modularity of java9 comes from a separate open source project called Jigsaw.

The project website: openjdk.java.net/projects/ji…

Why modularity

As Java developers know, there is a problem with developing applications in Java: Jar Hell, which is like DLL Hell in Windows.

Let’s say we start a small application that relies on a lot of JARS, as shown below:

Excerpted from: Mark Reinhold’s talk www.youtube.com/watch?v=l1s…

This is very common. While you could make the command line smaller by using “java-djava.ext.dirs =lib XXX”, there’s no denying that his classpath is that long. By the way, extdirs is no longer allowed in java9.

On the other hand, the JDK itself has a number of apis:

It’s too big for some small devices.

helloworld

I’m going to start with helloWorld. Before doing this, check your Java version:

java -version
java version "9"
Java(TM) SE Runtime Environment (build 9+181)
Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode)
Copy the code

If it is not java9, but 1.8, 1.7, then go slowly do not send.

Create the main class

Let’s start by creating a Java class called Demo.

File is saved as: SRC/com/pollyduan/modular/Demo. Java

package com.pollyduan.modular; public class Demo{ public static void main(String[] args){ System.out.println("hello modular."); }}Copy the code

Compile:

├── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ├ ── unregulated, unregulated, unregulated, unregulated, unregulatedCopy the code

Package the JAR and execute

$ mkdir lib

$ jar cvf lib/demo.jar -C classes .

$ java --class-path lib/demo.jar com.pollyduan.modular.Demo

hello modular.
Copy the code

— Class-path switch can be abbreviated:

$ java -cp lib/demo.jar com.pollyduan.modular.Demo
Copy the code

Of course we can specify the main class for the JAR to simplify running:

Main-Class: com.pollyduan.modular.Demo
Copy the code

You need to add the above line to manifest.mf to run it directly:

$ java -jar lib/demo.jar
Copy the code

Create a module

src/module-info.java

module hello{}
Copy the code

We write an empty module called Hello.

Compile the module

$ javac -d classes src/**.java
Copy the code

Decompile to see:

$ javap classes/module-info.class
Compiled from "module-info.java"
module hello {
  requires java.base;
}
Copy the code

Why did we write an empty module and decompile an extra line? Don’t worry about that. I’ll explain why later.

Packaged module

$ jar cvf lib/hello.jar -C classes .
$ jar tf lib/hello.jar
META-INF/
META-INF/MANIFEST.MF
module-info.class
com/
com/pollyduan/
com/pollyduan/modular/
com/pollyduan/modular/Demo.class
Copy the code

Run the module

$ java --module-path lib -m hello/com.pollyduan.modular.Demo

hello modular.
Copy the code

Unlike the traditional execution jar, there is no classpath, but module-path.

Similarly the command line can be abbreviated as:

java -p lib -m hello/com.pollyduan.modular.Demo
Copy the code

Can a module add main-class? The Java9 JAR provides a create switch, packaged in this way, to specify the main class for the Module:

$ jar --create --file lib/lib.jar --main-class com.pollyduan.modular.Demo -C classes .
Copy the code

Run the module again, and the command line becomes simpler.

$ java -p lib -m hello
Copy the code

Jigsaw’s design goals

Making it easier for developers to build and maintain a large library or application;

Improve the security and maintainability of the javaSE platform and JDK implementation;

Improve application performance;

On the Javase and JDK platforms, make applications smaller for deployment on smaller cells and tight cloud deployment systems.

What are the modules

To address these issues, the JDK wraps a layer on top of the package.

module -> package -> class/interface
Copy the code

What exactly is a module?

Modules are containers for packages. Applications that rely on it are called modules, and modules have names that other modules use. Module exports a specific package for use only by packages that depend on it.Copy the code

Module is a container for packages. Module only needs to export packages that the module depends on.

Create a Module

Declare a Module

cat module-info.java

module com.foo.bar{
  exports com.foo.bar.alpha;
  exports com.foo.bar.beta;
}
Copy the code

Like package-info.java, it is stored in a separate Java file called module-info.java.

Create the classes you want to export

For now, the contents of the class are not important. We can write an empty class, which lists only the directory structure:

$tree.. ├ ─ ─ com │ └ ─ ─ foo │ └ ─ ─ bar │ ├ ─ ─ alpha │ │ └ ─ ─ alpha. Java │ └ ─ ─ beta │ └ ─ ─ beta. Java └ ─ ─ the module - info. JavaCopy the code

Compile the module

│ ├── ├─ │ ├─ $Java module-info.java com/ ├─ │ ├─ $Java module-info.java com/ ├─ │ ├─ $Java module-info.java com/ ├─ │ ├─ $Java module-info.java com/ ├─ │ ├─ Class │ ├─ ├─ class │ ├─ class │ ├─ class │ ├─ class │ ├─ class │ ├─ class │ ├─ module-info module-info.javaCopy the code

Packaged module

The jar CVF com. Foo. Bar - 1.0. The jar.Copy the code

Check jar structure:

$jar tf com.foo.bar-1.0.jar meta-inf/meta-inf/manifest.mf module-info.class com/ com/foo/ com/foo/bar/ com/foo/bar/alpha/ com/foo/bar/alpha/Alpha.class com/foo/bar/beta/ com/foo/bar/beta/Beta.classCopy the code

Refer to the module

Now that we have the module com.foo.bar-1.0.jar, we can reference this module using the requires keyword when defining other modules.

module com.foo.app{
  requires co.foo.bar;
  requires java.sql;
}

module com.foo.bar{
  requires com.foo.baz;
  exports com.foo.bar.alpha;
  exports com.foo.bar.beta;
}

module com.foo.baz{
  exports com.foo.baz.mumble;
}
Copy the code

The built-in module

JDK native packages are merged into built-in modules, such as the java.base module:

module java.base{ exports java.io; exports java.lang; exports java.lang.annotation; exports java.lang.invoke; exports java.lang.module; exports java.lang.ref; exports java.lang.reflect; exports java.lang.math; exports java.lang.net; / /... }Copy the code

All applications will rely on java.base by default, just as we didn’t explicitly say “import java.lang.*;” before. The same.

“Requires java.base” : requires java.base = “requires java.base;” .

The following com.foo.app module does not need to explicitly introduce java.base:

If com.foo.bar adds a reference to the com.foo.baz module.

So, we know that com.foo.bar also implicitly introduces java.base.

In the same way, the com.foo.baz module implicitly references java.base:

Reliable configuration

Digging deeper, we know that java.sql references a number of other apis, so the following figure is not hard to understand.

The current module structure, called readable modules, provides reliable configurations.

If you reference a module that does not exist, you will also trigger xx not found, just like jar.

Compile time:

Runtime:

The type of access

If the referenced module does not export a class, it is not accessible, which is called strong encapsulation.

For example, the com.foo.bar module has an inner class BetaImpl:

So use BeatImpl in com.foo.bar’s active reference module com.foo.app as follows:

At compile time, an exception is raised:

Means: BetaImpl inaccessible because package com. Foo bar. Beta. Internal package not be exported.

Also, even if editing with an exported version succeeds and the runtime references an unexported version module:

View the built-in modules

$ jmod list $JAVA_HOME/jmods/java.base.jmod
classes/module-info.class
classes/apple/security/AppleProvider$1.class
...
classes/java/lang/Object.class
...
bin/java
bin/keytool
...
conf/security/java.policy
...
Copy the code

See more built-in modules:

$ java --list-modules java.activation@9 java.base@9 java.compiler@9 java.corba@9 java.datatransfer@9 java.desktop@9 / /... Save spaceCopy the code

The helloworld advanced

Add a module dependency from the HelloWorld base.

Let’s review the helloWorld directory structure:

$tree Module Module ├─ class │ ├─ com │ ├─ ├── modular │ │ ├─ class-module-info ├ ─ ─ lib │ ├ ─ ─ demo. The jar │ ├ ─ ─ hello.html jar └ ─ ─ the SRC ├ ─ ─ com │ └ ─ ─ pollyduan │ └ ─ ─ modular │ └ ─ ─ demo. Java └ ─ ─ module-info.javaCopy the code

Add a module service where the service directory is the same as the module directory.

$├─ ├─ com ├─ ├─ class ├─ class ├─ class ├─ class ├─ class ├─ classCopy the code

Creating a Service Class

service/src/com/pollyduan/service/HelloService.java

package com.pollyduan.service; public class HelloService{ public void sayHi(String name){ System.out.println("Hello "+name); }}Copy the code

Declare the Service module

service/src/module-info.java

module service{
    exports com.pollyduan.service;
}
Copy the code

Compiling the Service module

$javac - d service/classes service/SRC/Java $* * tree service/classes/service/classes / ├ ─ ─ com │ └ ─ ─ pollyduan │ └ ─ ─ Class │ ├ ─ garbage, ├ ─ garbage, ├ ─ garbageCopy the code

Package the Service module

jar --create --file service/lib/service.jar -C service/classes/ .
Copy the code

Modify the HelloWorld module

module/src/module-info.java

module hello{
    requires service;
}
Copy the code

Modify the HelloWorld main class to use methods in Service

module/src/com/pollyduan/modular/Demo.java

package com.pollyduan.modular; import com.pollyduan.service.HelloService; public class Demo{ public static void main(String[] args){ new HelloService().sayHi("java9 modular."); }}Copy the code

Recompile the package HelloWorld

$ javac -p service/lib -d module/classes module/src/**java

$ jar --create --file module/lib/hello.jar -p service/lib --main-class com.pollyduan.modular.Demo -C module/classes .

$ java -p module/lib:service/lib -m hello
Hello java9 modular.
Copy the code

Call it a day.

Module related tools

The original javac/ JavAP, etc., will not be mentioned, here are just a few new ones. More reference: docs.oracle.com/javase/9/to…

jlink

Module consolidation tool for aggregating, optimizing, and packaging a series of modules into a custom image. This is a JRE image, not a JAR.

If we only reference the java.base module, then we can optionally package when we can:

$ jlink -p $JAVA_HOME/jmods --add-modules java.base --output jre
Copy the code

The output JRE is a full working JRE, which differs greatly in size from the native JDK:

$ du -sh $JAVA_HOME jre
493M	/Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home
 35M	jre
Copy the code

This way, we can pack our own modules in.

$ mkdir jmods
$ jmod create --class-path service/lib/service.jar jmods/service.jmod
$ jmod create --class-path module/lib/hello.jar jmods/module.jmod
$ jlink -p $JAVA_HOME/jmods:jmods --add-modules java.base,hello --output jre

$ cat jre/release
JAVA_VERSION="9"
MODULES="java.base service hello"

./jre/bin/java --list-modules
hello
java.base@9
service
Copy the code

Note that module-path values use the same separators as CLASspath, such as semicolons on Windows and colons on Linux; The values of the add-modules switch are comma-separated.

Thus, we have packaged a 30M JRE, and we have packaged our own Module. And then what? Direct execution module look:

$ ./jre/bin/java -m hello

Hello java9 modular.
Copy the code

Jlink also provides a launcher switch that compiles our modules into executable files, the same as Java commands, in the JRE /bin.

$ jlink -p $JAVA_HOME/jmods:jmods --add-modules java.base,hello --launcher Hello=hello --output jre

$ ls jre/bin
Hello   java    keytool

$ ./jre/bin/Hello
Hello java9 modular.
Copy the code

Notice the format of the launcher: “[command]=[module]”, the command is capitalized to distinguish it.

The jlink switch has many functions, including the following functions to compress the already small JRE:

$ jlink -p $JAVA_HOME/jmods:jmods --add-modules java.base,hello --launcher Hello=hello \
--compress 2 --strip-debug \
--output jre_mini

$ du -sh jre*
 35M	jre
 21M	jre_mini
Copy the code

jdeps

This is a dependency parser for Java class files.

$ jdeps --module-path service/lib module/lib/hello.jar hello [file:///Users/pollyduan/tmp/java/java9/module/lib/hello.jar] requires mandated java.base (@9) requires service hello ->  java.base hello -> service com.pollyduan.modular -> com.pollyduan.service service com.pollyduan.modular -> java.lang java.baseCopy the code

jmod

Used to create JMOD files and view existing JMOD files.

Create jmod file:

$ jmod create --class-path . com.foo.bar.jmod $ jmod list com.foo.bar.jmod classes/module-info.class classes/.com.foo.bar.jmod.tmp classes/com/foo/bar/alpha/Alpha.class classes/com/foo/bar/alpha/Alpha.java Classes/com/foo/bar/beta/beta. Class classes/com/foo/bar/beta/beta. Java classes/com foo bar - 1.0. The jar classes/module-info.javaCopy the code

jdeprscan

This is a static analysis tool for the JAR, looking for the API that it depends on.

$jdeprscan dom4j-1.6.1.jar Jar file dom4j-1.6.1.jar Class org/dom4j/bean/BeanMetaData use outdated approach Java/lang/Integer: : < init > error: (I) V Can't find the org/relaxng datatype/DatatypeException error: can't find the class MSV/datatype/XSD/com/sun/XSDatatype error: Can't find the kind of com/sun/MSV/datatype/DatabindableDatatype error: can't find the kind of com/sun/MSV/datatype/SerializationContext error: Can't find the class MSV/datatype/XSD/com/sun/TypeIncubator error: Can't find the class MSV/datatype/XSD/com/sun/DatatypeFactory class org/dom4j/IO/SAXEventRecorder use outdated method of Java/lang/Integer: : < init > (I) V Class org/dom4j/IO/SAXHelper use outdated org/XML/sax/helpers/XMLReaderFactory class org/dom4j/IO/SAXReader use outdated classes Org/XML/sax/helpers/XMLReaderFactory error: can not find the org/xmlpull/v1 / XmlPullParserFactory error: Can't find the kind of org/xmlpull/v1 / XmlPullParser error: can not find the org/GJT/XPP XmlPullParserFactory error: can't find the kind of org/GJT/XPP/XmlPullParser error: Unable to find class org/jaxen/XPath error: Can't find the kind of org/jaxen VariableContext class org/dom4j/tree/NamespaceCache use outdated methods Java/lang/Integer: : < init > (I) V class Org/dom4j/tree/NamespaceCache use outdated method of Java/lang/Float: : < init > V (F) error: can't find the kind of org/jaxen/the NamespaceContext error: Can't find the kind of org/jaxen SimpleNamespaceContext error: can not find the org/jaxen/dom4j Dom4jXPath error: can't find the kind of org/jaxen JaxenException error: Can't find the kind of org/jaxen/pattern/pattern error: can not find the org/jaxen/Context error: can't find the kind of org/jaxen/pattern/PatternParser error: Can't find the org/jaxen saxpath/SAXPathException error: can not find the org/jaxen/ContextSupport error: can't find the kind of org/jaxen XPathFunctionContext error: Can't find the kind of org/jaxen SimpleVariableContext error: can not find the org/jaxen/dom4j DocumentNavigator error: can't find the kind of org/GJT/XPP/XmlStartTagCopy the code

Module summary

keywords

Java module descriptor module-info.class modular jar files Module JAR file Jmod Files Module manifest file Observable Modules readable Modules => reliable Configuration Accessible types => Strong encapsulationCopy the code

The difference between Module and JAR

A JAR is really just a collection of class files, like a ZIP document; Module, on the other hand, is a canonical Java component with more tool support than jar. Resources in the JAR can be used arbitrarily; Resources in the Module can only be used if they are exported. Module is still a JAR carrier. In a physical sense, module can be understood as a module-info.class in a JAR. ├─ bin ├─ classes ├─ SRC Project ├─ bin ├─ classes ├─ SRC ├── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ─Copy the code

Module issues to be aware of

Module dependencies also have cyclic dependencies, which need attention. Module A, requires B; Module B has requires A.

Does the IDE support it? Traditional ides, which manage projects based on classpath, now need to support module-Path

Module packages jars that you can still use as normal jars, and no one is stopping you, at least for now. This is not to say that modules are completely meaningless, just as members in class files are private and not accessible externally. You can access them by reflection.

Application scenarios of modules

First, the most prominent use is to use JLink to package custom images and distribute them to run in small cells, such as Docker, embedded devices.

Second, there will surely be more and more containers to support running modules directly.

It then has a place in the hot-swappable plug-in scenario for applications.

Finally, there is the way modules run instead of jar.

Wait and see.