[JAVA] Notes d'étude de puzzle

Une note de l'étude de Java 9 Project Jigsaw.

environnement

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

Structure des dossiers

|-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

Code source

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;
}

compiler

#Compilez le sous-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

#Compilez le module principal
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java

Exécuter

> java -p main\class;sub\class -m sample_module.main/sample.main.Main
FooImpl.hello()

La description

Déclaration de module dépendant

sub/src/module-info.java


module sample_module.sub {
    exports sample.sub;
    exports sample.sub.api;
}

--Déclarez le module dans un fichier spécial appelé module-info.java placé dans le paquet racine. --Le nom est fixé à module-info.java --La déclaration du module est décrite au format module <nom du module> {<définition du module>}

Déclaration du module de référencement

main/src/module-info.java


module sample_module.main {
    requires sample_module.sub;
}

--Le côté qui fait référence à d'autres modules décrit également la déclaration du module en utilisant module-info.java ainsi que le côté référencé. --requries définit le module dont dépend ce module

Spécification du module au moment de la compilation

#Compilation du sous-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

#Compilation du module principal
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java

--Compile utilise toujours la commande javac --S'il n'y a pas de modules dépendants, vous pouvez compiler avec les spécifications conventionnelles (compilation de sous-modules)

Spécification du module et spécification de la classe principale au démarrage

> java -p main\class;sub\class -m sample_module.main/sample.main.Main

Comportement lors du référencement de packages qui ne sont pas exportés

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();
    }
}

État d'erreur de compilation


> 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:Erreur:Échantillon de paquet.sub.interne ne peut pas être affiché
import sample.sub.internal.FooImpl;
                 ^
  (Échantillon de paquet.sub.interne est l'exemple de module_module.Déclaré en sous mais non exporté)
1 erreur

De cette manière, vous ne pouvez pas faire référence à des paquets qui ne sont pas des «exportations».

Emballage et utilisation en pot

Essayez d'utiliser le programme Hello World en emballant à la fois le principal et le sous-jar dans un bocal.

Idem pour compiler avec javac.

Paquet en pot

#Créer un pot pour le sous-module
> jar -c -f sub\jar\sub-module.jar -C sub\class .

#Créez un pot pour le module principal
> jar -c -f main\jar\main-module.jar -C main\class .

--Utilisez la commande jar comme précédemment pour créer le fichier jar du module ---c est une commande qui signifie créer un pot (abréviation de --create) --Spécifiez la destination de sortie avec -f <chemin de destination de sortie jar> -- -C <répertoire du package> . pour empaqueter le répertoire spécifié dans le fichier jar

Reportez-vous aux informations du module de jar

#Informations sur le sous-module de sortie
> 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

#Informations de sortie du module principal
> 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) peut afficher les informations de module de jar. --ʻExports est un package public --requires est le module dépendant --java.base est un module qui inclut le package java.lang, et il est toujours fourni avec lui même si vous ne le spécifiez pas. --contains` est probablement un paquet privé

Exécuter

> java -p sub\jar;main\jar -m sample_module.main/sample.main.Main
FooImpl.hello()

--Si vous spécifiez le dossier avec le module (jar) avec -p, il semble que le fichier jar y sera lu.

Type de module

Il existe trois principaux types de modules.

  1. named module
  2. automatic module
  3. unnamed module

named module Un module avec des informations de définition (module-info.class) lues par le chemin du module ( --module-path). Lorsque nous parlons de modules, nous y faisons souvent référence.

automatic module Un fichier jar sans informations de définition lu dans le chemin du module.

Tous les paquets sont traités comme des «exportations». De plus, le nom du module est automatiquement complété à partir du nom du fichier jar.

C'est le cas si vous spécifiez un fichier jar créé avant Java 9 avec --module-path.

Je n'ai pas trouvé de définition claire, mais il semble que ce doit être un fichier jar car le nom du module est complété à partir du nom du fichier. Javadoc a également la description suivante, donc je pense qu'il doit être au moins un pot.

A JAR file that does not have a module-info.class in its top-level directory defines an automatic module (Traduction) Les fichiers Jar qui n'ont pas module-info.class au niveau supérieur définissent un module automatique

http://download.java.net/java/jigsaw/docs/api/java/lang/module/ModuleFinder.html#of-java.nio.file.Path...-

unnamed module Modules chargés avec le chemin de classe (--class-path). Tous les paquets sont traités comme des «exportations».

Combinez chaque module

Essayez différentes combinaisons de chaque module (module nommé, module automatique, module sans nom).

Si vous comptez d'abord les résultats,

jigsaw.jpg

Ça ressemble à ça.

Mise en œuvre (commune)

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 est ceci, donc je vais l'omettre.

named module -> automatic module

Structure des dossiers


|-main/
| |-class/
| `-src/
|   |-module-info.java
|   `-sample/main/
|     `-Main.java
|
`-sub/
  |-class/
  `-src/
    `-sample/sub/
      `-Sub.java

Compilation du sous-module


#compiler
> javac -d sub\class sub\src\sample\sub\Sub.java

#création de pot
> 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;
}

Compilez et lancez le module principal


#Compilation du module principal
> javac -p sub\jar\no_module-sub.jar -d main\class main\src\module-info.java main\src\sample\main\Main.java

#Commencez
> java -p sub\jar\no_module-sub.jar;main\class -m sample_module.main/sample.main.Main
Sub.method()

--Définissez le sous-module sur -p ( --module-path) et démarrez-le

Logique de détermination automatique du nom du module pour le module automatique

  1. Attribut du fichier manifeste ʻAutomatic-Module-Name`
  2. Déterminé automatiquement à partir du nom du fichier s'il n'est pas spécifié dans le fichier manifeste

named module -> unnamed module Je n'arrive pas à le faire.

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:Erreur:Échantillon de paquet.le sous n'existe pas
import sample.sub.Sub;
                 ^
main\src\sample\main\Main.java:7:Erreur:Impossible de trouver le symbole
        Sub sub = new Sub();
        ^
symbole:Sous-classe
endroit:Classe principale
main\src\sample\main\Main.java:7:Erreur:Impossible de trouver le symbole
        Sub sub = new Sub();
                      ^
symbole:Sous-classe
endroit:Classe principale
3 erreurs

Même si je place jar dans le chemin de la classe (-cp), la classe ne peut pas être lue.

automatic module -> named module

Structure des dossiers


|-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;
}

Compilation du sous-module


#compiler
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java

#création de pot
> jar -c -f sub\jar\module-sub.jar -C sub\class .

Compiler le module principal


#compiler
> javac -d main\class --add-modules sample_module.sub -p sub\jar\module-sub.jar main\src\sample\main\Main.java

#création de pot
> jar -c -f main\jar\no_module-main.jar -C main\class .

Courir


> 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()

C'est une imagination qui regarde Togetter of the Gods, donc cela peut ou non être différent.

automatic module -> automatic module

Structure des dossiers


|-main/
| |-class/
| `-src/
|   `-sample/main/
|     `-Main.java
|
`-sub/
  |-class/
  `-src/
    `-sample/sub/
      `-Sub.java

Compilation du sous-module


#compiler
> javac -d sub\class sub\src\sample\sub\Sub.java

#création de pot
> jar -c -f sub\jar\no_module-sub.jar -C sub\class .

Compiler le module principal


#compiler
> 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 .

Commencez


> 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()

--Cela peut également être exécuté en spécifiant --add-modules.

automatic module -> unnamed module

Compilation du sous-module


#compiler
> javac -d sub\class sub\src\sample\sub\Sub.java

#création de pot
> jar -c -f sub\jar\no_module-sub.jar -C sub\class .

Compiler le module principal


#compiler
> 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 .

Courir


> java -p main\jar\no_module-main.jar -cp sub\jar\no_module-sub.jar -m no.module.main/sample.main.Main
Sub.method()

--Peut être traité comme un module sans nom en définissant un fichier jar non-module dans le chemin de classe avec -cp

unnamed module -> named module

Structure des dossiers


|-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;
}

Compilation du sous-module


#compiler
> 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 .

Compiler le module principal


#compiler
> javac -p sub\jar\module-sub.jar --add-modules sample_module.sub -d main\class main\src\sample\main\Main.java

#création de pot
> jar -c -f main\jar\no_module-main.jar -C main\class .

Courir


> java -p sub\jar\module-sub.jar -cp main\jar\no_module-main.jar --add-modules sample_module.sub sample.main.Main
Sub.method()

unnamed module -> automatic module

Structure des dossiers


|-main/
| |-class/
| `-src/
|   `-sample/main/
|     `-Main.java
|
`-sub/
  |-class/
  `-src/
    `-sample/sub/
      `-Sub.java

Compilation du sous-module


#compiler
> javac -d sub\class sub\src\sample\sub\Sub.java

#création de pot
> jar -c -f sub\jar\no_module-sub.jar -C sub\class .

Compiler le module principal


#compiler
> javac -p sub\jar\no_module-sub.jar -d main\class --add-modules no.module.sub main\src\sample\main\Main.java

#création de pot
> jar -c -f main\jar\no_module-main.jar -C main\class .

Courir


> 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()

unnamed module -> unnamed module

Compilation du sous-module


#compiler
> javac -d sub\class sub\src\sample\sub\Sub.java

#création de pot
> jar -c -f sub\jar\no_module-sub.jar -C sub\class .

Compiler le module principal


#compiler
> javac -d main\class -cp sub\jar\no_module-sub.jar main\src\sample\main\Main.java

#création de pot
> jar -c -f main\jar\no_module-main.jar -C main\class .

Courir


> java -cp sub\jar\no_module-sub.jar;main\jar\no_module-main.jar sample.main.Main
Sub.method()

Il s'agit essentiellement d'une méthode sans module, c'est-à-dire qu'elle est dans le même état que la compilation et l'exécution normales sous Java 8 ou moins.

nécessite un modificateur

L'un des deux modificateurs suivants peut être défini dans «requires».

transitive

Dépendances de module


A -> B -> C

Supposons qu'un module «B» dépend de «C». C'est ce qualificatif «transitif» qui permet à «C» de créer automatiquement «requires» lorsqu'un autre module «A» charge «B» avec «requires».

Premièrement, s'il n'y a pas de transitif

Structure des dossiers


|-A/
| `-src/
|   |-module-info.java
|   `-a/
|     `-A.java
|-B/
| `-src/
|   |-module-info.java
|   `-b/
|     `-B.java
`-C/
  `-src/
    |-module-info.java
    `-c/
      `-C.java

** module C **

C.java


package c;

public class C {}

C/src/module-info.java


module module_c {
    exports c;
}

** module B **

B.java


package b;

import c.C;

public class B {}

B/src/module-info.java


module module_b {
    requires module_c;
    exports b;
}

** Un 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;Essayez sans avoir besoin du module C
    exports a;
}

compiler

#Module de compilation C
> javac -d c\class C\src\module-info.java C\src\c\C.java

#Module de compilation B
> javac -p c\class -d b\class B\src\module-info.java B\src\b\B.java

#Compiler un 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:Erreur:Le package c ne peut pas être affiché
import c.C;
       ^
  (Le package c est le module module_Déclaré en c, mais module module_Non chargé dans un)
1 erreur

Le package «c» ne peut pas être référencé car le module A ne requiert pas explicitement le module C.

Utiliser transitive

B\src\module-info.java


module module_b {
    requires transitive module_c;
    exports b;
}
#Module de compilation B
> javac -p c\class -d b\class B\src\module-info.java B\src\b\B.java

#Compiler un module
> javac -p c\class;b\class -d a\class A\src\module-info.java A\src\a\A.java

static Utilisez static pour les modules qui sont" requis au moment de la compilation mais facultatifs au moment de l'exécution ".

S'il n'y a pas de statique

Structure des dossiers


|-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;
}

Essayez de compiler.

compiler


#Compilation du sous-module
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java

#Compilation du module principal
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java main\src\sample\main\SubFactory.java

La compilation passe. Ensuite, essayez de l'exécuter.

> 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

Une erreur s'est produite car le sous-module n'a pas pu être trouvé.

Lorsque la statique est ajoutée

main\src\module-info.java


module sample_module.main {
    requires static sample_module.sub;
}

Ajoutez static et compilez et exécutez de la même manière.

#Compilation du module principal
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java main\src\sample\main\SubFactory.java

#Courir
> java -p main\class -m sample_module.main/sample.main.Main
Hello World!!

J'ai pu l'exécuter.

open Il ne peut pas être référencé au moment de la compilation, mais il peut être contrôlé afin qu'il puisse être référencé au moment de l'exécution. Cela sera utilisé lorsque vous référencerez le code à l'aide de la réflexion.

Il existe deux types, ʻopens, qui est défini pour chaque paquet, et ʻopen module, qui est défini pour l'ensemble du module.

opens

Structure des dossiers


|-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 {
    //Tout d'abord, créez-le sans le publier du tout
}

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);
    }
}

Le package sample.sub n'est pas directement référencé, et la méthode Sub.sub () est exécutée en utilisant la réflexion.

main/src/module-info.java


module sample_module.main {
    requires sample_module.sub;
}

Essayez de compiler.

#Compilation du sous-module
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java

#Compilation du module principal
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java

sample.sub n'est pas référencé statiquement, il se compile donc. Mais quand tu fais ça.

> 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` est levée.

Publiez sample.sub avec ʻopens` et réessayez.

sub\src\module-info.java


module sample_module.sub {
    opens sample.sub;
}

Compiler et exécuter


#Compilation du sous-module
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java

#Compilation du module principal
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java

#Courir
> java -p sub\class;main\class -m sample_module.main/sample.main.Main
Sub.sub()

Cette fois, cela a bien fonctionné.

Au fait, si vous faites référence au package sample.sub dans Main.java dans cet état (ʻopens sample.sub;`), ce sera comme suit.

Main.java


package sample.main;

import sample.sub.Sub;

public class Main {
    public static void main(String... args) throws Exception {
        new Sub().sub();
    }
}

Normalement, «Sub» est «nouveau» pour exécuter la méthode.

compiler


#Compilation du module principal
> 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:Erreur:Échantillon de paquet.le sous ne peut pas être affiché
import sample.sub.Sub;
             ^
  (Échantillon de paquet.sub est l'exemple de module_module.Déclaré en sous mais non exporté)
1 erreur

Le package sample.sub est simplement ʻopens, pas ʻexports. Par conséquent, si vous essayez d'y faire référence de manière statique au moment de la compilation, une erreur se produit.

Pour résumer la disponibilité de la référence à chaque moment,

Moment de référence opens exports
Au moment de la compilation ×
Durée

Comme ça.

open module ʻOpens est un paramètre pour un paquet spécifique, mais si vous spécifiez ʻopen module, ʻopens` est appliqué à l'ensemble du module.

Structure des dossiers


|-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;
}

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);
    }
}

--La classe Sub est référencée statiquement pour exécuter la méthode

Compiler et exécuter


#Compilation du sous-module
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java sub\src\sample\sub\foo\Foo.java

#Compilation du module principal
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java

#Courir
> java -p sub\class;main\class -m sample_module.main/sample.main.Main
Sub.sub()
Foo.foo()

--sample.sub.foo.Foo n'a pas déclaré ʻopens ou ʻexports, mais il peut être référencé par réflexion.

use, provides ServiceLoader peut être défini dans module-info.java à partir de Java 9.

la mise en oeuvre

Structure des dossiers


|-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;
}

Contrôle de fonctionnement

compiler


#Compilation du module fournisseur
> javac -d provider\class provider\src\module-info.java provider\src\sample\provider\api\Foo.java provider\src\sample\provider\impl\FooImpl.java

#Compilation du module utilisateur
> javac -d user\class -p provider\class user\src\module-info.java user\src\sample\user\Main.java

Courir


> java -p provider\class;user\class -m sample_module.user/sample.user.Main
FooImpl.foo()

La description

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;
}

Il semble que vous devez être conscient qu'il existe plus de méthodes de déclaration, comme lors de la lecture du code du framework OSS.

[^ 1]: Classe qui implémente "service" [^ 2]: Interfaces, classes abstraites, etc.

jlink Vous pouvez utiliser la commande jlink pour créer un environnement d'exécution Java (sous-ensemble) qui ne contient que le strict minimum de modules. Même si JRE n'est pas installé dans la destination de distribution, vous pouvez démarrer l'application en incluant le sous-ensemble créé par jlink.

la mise en oeuvre

Structure des dossiers


`-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 {
}

Créer un sous-ensemble

#compiler
> javac -d class src\module-info.java src\sample\jlink\Main.java

#création de pot
> jar -c -f jar\module-jlink.jar -C class .

#Créer un runtime avec jlink
> jlink -p .\jar;%JAVA_HOME%\jmods --add-modules sample_module.jlink --output .\output

--Dans la commande jlink, spécifiez au moins ce qui suit - -p (--module-path) --Spécifiez le chemin où se trouve le module à inclure

L'application avec runtime est sortie dans le dossier ʻoutput` comme indiqué ci-dessous.

`-output/
  |-bin/
  |-conf/
  |-include/
  |-legal/
  |-lib/
  `-release

Sous bin se trouve le fichier java.exe, qui est la commande java pour le sous-ensemble.

#Accédez à la corbeille du sous-ensemble
> cd output\bin

#Vérifiez les modules inclus
> java --list-modules
java.base@9
sample_module.jlink

Le sous-ensemble contient uniquement les modules minimum requis (java.base et sample_module.jlink).

Essayez de démarrer le programme.

> java -m sample_module.jlink/sample.jlink.Main
Hello jlink!!

sample_module.jlink est intégré au runtime, vous n'avez donc pas besoin de le spécifier avec -p.

À propos, la taille du runtime créé était de 35,9 Mo lorsque je l'ai vérifiée avec l'Explorateur Windows.

Compresse

Peut être compressé dans une certaine mesure en option.

> jlink --compress=2 -p .\jar;%JAVA_HOME%\jmods --add-modules sample_module.jlink --output .\output

--Compression peut être spécifiée avec --compress = N.

-c, --compress=<0|1|2> Enable compression of resources:
                       Level 0: No compression
                       Level 1: Constant string sharing
                       Level 2: ZIP

Générer un fichier de démarrage

La nécessité de spécifier la classe principale avec -m au démarrage n'est pas très bonne lors de la distribution à des personnes qui ne sont pas familiarisées avec Java. Dans ce cas, il est pratique de générer un fichier script pour le démarrage.

> jlink --launcher jlink-hello=sample_module.jlink/sample.jlink.Main  -p .\jar;%JAVA_HOME%\jmods --add-modules sample_module.jlink --output .\output

--Spécifiez --launcher <nom de la commande> = <classe principale>

#Passer sous la poubelle
> cd output\bin

#Exécuter le script de démarrage
> jlink-hello.bat
Hello jlink!!

Le fichier de script généré a le contenu suivant.

jlink-hello.bat


@echo off
set JLINK_VM_OPTIONS=
set DIR=%~dp0
"%DIR%\java" %JLINK_VM_OPTIONS% -m sample_module.jlink/sample.jlink.Main %*

Le script shell pour Linux a également été produit, mais peut-il être démarré?

Examiner les modules dépendants

Vous pouvez utiliser la commande jdeps pour savoir de quel module dépend le fichier jar. Lorsque vous ajoutez un fichier jar non module existant, vous saurez quel module de la bibliothèque standard ajouter.

Pour tester, consultez 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

Le fait d'alimenter le pot avec l'option -s vous montrera les modules dépendants.

java.desktop est un module qui inclut awt et swing, mais il y a des beans et ainsi de suite. Je vois.

Si le fichier jar est un module nommé, vous devez spécifier le module dépendant avec --module-path (enfin, bien sûr, cela semble bizarre d'avoir un module dépendant pour rechercher le module dépendant. Faire).

référence

Recommended Posts

Notes d'étude de puzzle
Notes d'étude JavaFX
Notes d'étude Docker
[Java] Notes d'étude
Notes de puzzle à Gradle
Notes d'étude de base de Maven
Notes d'étude de classe interne et de style lambda
JUnit 4 notes
Politique d'étude
note java
Notes de l'étude Spring Framework [Partie 1] Conteneur DI
notes synchronisées