Java Platform Module System (JPMS) は、依存関係とパッケージのカプセル化を明示的にします。名前付きモジュールには記述子 module-info.java がソースルートに含まれます。コンパイルすると、展開されたモジュールディレクトリまたはモジュール化された JAR に module-info.class が生成されます。
module com.example.app {
requires com.example.codec;
uses com.example.codec.Decoder;
}
module com.example.codec {
exports com.example.codec.api;
exports com.example.codec.internal to com.example.app;
opens com.example.codec.model to com.example.json;
provides com.example.codec.Decoder with com.example.codec.JsonDecoder;
}コンパイル、パッケージ化、起動 #
従来のマルチモジュールソースツリーでは、モジュールソースパス以下にモジュールごとのディレクトリを置きます。次のようにコンパイルします。
javac --module-source-path src -d out -m com.example.app,com.example.codec
jar --create --file app.jar --main-class com.example.app.Main -C out/com.example.app .
java --module-path libs:app.jar --module com.example.appjar --main-class は実行可能なメインクラスを記録しますが、起動時に java -m module/name.Main で 1 つを指定できるため任意です。jlink はモジュールの推移閉包からランタイムイメージを作成します。モジュールパス上のモジュール化された JAR と JMOD を受け入れますが、JMOD はランタイム成果物ではありません。
jlink --module-path "$JAVA_HOME/jmods:libs" \
--add-modules com.example.app --output image
image/bin/java -m com.example.app可読性とカプセル化 #
requires はモジュールを可読にします。requires transitive はその可読性を依存モジュールへ再エクスポートし、requires static はコンパイル時には必須ですが実行時には任意です。exports は、すべての可読モジュールに対して、または to を使った名前付きリストに対して、パッケージ内の public 型へのコンパイル時および通常の実行時アクセスを許可します。opens は通常の型アクセスを許可せずに深いリフレクションを許可し、open module はすべてのパッケージを開きます。フレームワーク統合には限定的な opens を優先してください。
uses と provides ... with ... はモジュール記述子内でサービスを宣言します。ServiceLoader はモジュール解決中にこれらの宣言を使用します。パッケージはモジュールから独立したアクセス単位ではないため、public であるだけではエクスポートされていないパッケージを迂回できません。
解決と移行 #
各フェーズでは、モジュールパスとシステムモジュールおよびアップグレードモジュールが、観測可能なモジュールの集合を形成します。解決はルートモジュールから始まり、requires エッジをたどります。同じ名前のモジュールが重複すると、クラスパスの順序で選択されるのではなく失敗します。名前付きモジュールには分割パッケージを含められません。解決された 2 つの名前付きモジュールに同じパッケージがあるとエラーになります。この規則によって、パッケージの所有権とカプセル化が決定論的になります。
クラスパスのコードは名前のないモジュールに属します。解決された名前付きモジュールのエクスポートされたパッケージを読み取り、そのパッケージはエクスポートおよびオープンされていますが、名前付きモジュールは名前のないモジュールに対する requires を宣言できません。モジュール化されていない JAR はモジュールパス上では自動モジュールになります。派生名またはマニフェスト名を持ち、解決されたすべてのモジュールを読み、すべてのパッケージをエクスポートおよびオープンします。自動モジュールは段階的な移行に役立ちますが、意味のあるカプセル化は提供しません。モジュール境界に依存する前に、明示的な記述子に置き換えてください。
名前付きモジュールの境界を越えるリフレクションには、通常のアクセス可能性に加えて、深いアクセスのためにオープンなパッケージが必要です。--add-exports と --add-opens は移行またはデプロイ時のオーバーライドであり、モジュールが所有する記述子の代替ではありません。
コメント
GitHub で閲覧・コメントする(投稿にはログインが必要です)