torutkのブログ

ソフトウェア・エンジニアのブログ

「The Java Module System」を読む会これまでのまとめ(その2) #javareading

Java読書会「The Java Module System」を読む会(第1~3回)のまとめ(その2)

torutk.hatenablog.jp

の続きです。

第2章 Anatomy of a modular application

モジュール化したアプリケーションのディレクトリ構成の例
  +- libs    (サードパーティの依存物)
  +- mods    (コンパイル&パッケージ化したモジュール)
  +- monitor   (アプリケーションモジュールの1つ)
  |     +- src
  |     |    +- main
  |     |         +- java  (モジュールのソースコードを含む)
  |     |              +- monitor
  |     |              +- module-info.java  (モジュールの宣言)
  |     +- target
  |          +- classes         (モジュールのコンパイル結果を格納)
  +- monitor.observer (モジュール)
  |     +- src
  • 慣例で、modsフォルダーに生成したモジュールを格納
モジュール化するアプリケーションの作成の流れ
  1. アプリケーションをモジュールに分解する(関心事の分離戦略がよい)
  2. ディレクトリ構造の作成
  3. モジュール宣言
  4. 別モジュールへの依存関係の宣言
  5. モジュール公開APIの定義
  6. モジュールグラフの可視化
  7. コンパイルとパッケージ化
他のモジュールに依存のないモジュールのビルド
$ java -d monitor.observer/target/classes ${source-files}
$ jar --create --file mods/monitor.observer.jar
 -C monitor.observer/target/classes .
他のモジュールに依存のあるモジュールのビルド
$ java --module-path mods
 -d monitor.observer.alpha/target/classes ${source-files}
$ jar --create --file mods/monitor.observer.alpha.jar
 -C monitor.observer.alpha/target/classes .

依存するモジュールのあるフォルダを --module-pathオプションで指定します。

2つのフォルダにあるモジュールに依存のあるモジュールのビルド

アプリケーションのモジュールとサードパーティのモジュールとに依存のあるモジュールをビルドします。 --module-pathオプションで複数のフォルダを指定可能です。

$ javac --module-path mods:libs
 -d monitor.rest/target/classes ${source-files}
$ jar --create --file mods/monitor.rest.jar
 -C monitor.rest/target/classes .
メインメソッドを持つクラスを含むモジュールのビルド
$ javac --module-path mods
 -d monitor/target/classes ${source-files}
$ jar --create --file mods/monitor.jar
 --main-class monitor.Monitor
 -C monitor/target/classes .
アプリケーションの実行
$ java --module-path mods:libs --module monitor

モジュールパスでモジュールを収容するフォルダを指定、メインを持つモジュールの名前を指定して実行します。

第3章 Defining modules and their properties

2つのモジュールファイルフォーマット
  • JMOD
    JDKを構成するモジュールはJMODフォーマットで提供されています。アプリケーション開発者にはJMODファイルを生成する機能は提供されていません
  • モジュラーJAR 通常のJARファイル内のルートディレクトリにモジュール記述子module-info.classが含まれているものです。

モジュラーJARをクラスパスに置くと、モジュール定義が無視され従来のJARファイルとして扱われます。

モジュール宣言(module-info.java
module モジュール名 {
    requires モジュール名;
    exports パッケージ名;
}

モジュール名とパッケージ名の両方が登場し、命名規則が類似しているので混乱しがちです。

ルートモジュールからの依存性解析結果に含まれないモジュールは使用できません。 そこで、javaコマンドのオプション --add-modules や --add-reads で補うことができます。

  • --add-modulesは、指定したモジュール群を、ルートモジュールとして扱う
  • --add-readsは、指定したモジュールから、指定したターゲットモジュール群へrequiresなしでもアクセス可能とする

モジュール宣言(module-info.java)をコンパイルして生成されるクラスmodule-info.classは、モジュール記述子と呼びます。

モジュール名を付けるには次が重要です。

  • グローバルユニーク
  • 安定

ベストな命名は、ドメイン名の逆順です。これはパッケージ名の命名と同じルールです。そのため、モジュールに含まれるパッケージのパッケージ名のプレフィックスをモジュール名にするとよいです。

モジュールの種類
  • アプリケーションモジュール
    JDK以外のモジュール。モジュールパス上に置き、モジュラーJAR形式
  • イニシャルモジュール
    コンパイル開始対象モジュール、またはmainメソッドを持つモジュール
  • ルートモジュール
    JPMSが依存関係解決にとりかかる対象モジュールで、イニシャルモジュールはルートモジュールでもある
  • プラットフォームモジュール
    JDKを構成するモジュール。JMODファイルで提供
  • インキュベーターモジュール
    非標準なプラットフォームモジュール。jdk.incubator.*
  • システムモジュール
    プラットフォームモジュールのサブセットで実行イメージ用に抜粋したものと、jlinkが追加したアプリケーションモジュールから構成。
    java --list-modules で一覧されるもの。
  • オブザーバブルモジュール
    現在のランタイムにあるすべてのプラットフォームモジュールと、コマンドラインで指定したアプリケーションモジュール
  • ベースモジュール
    java.base
  • 明示的なモジュール
    プラットフォームモジュールと、モジュール記述子(module-info.class)を持つアプリケーションモジュール
  • 自動モジュール
    モジュール記述子を持たない、名前が指定されたモジュール(モジュールパスに置いたプレーンJAR)
  • 名前付きモジュール
    明示的なモジュールと自動モジュールの総称。モジュール記述子で定義した名前またはJPMSが推論した名前
  • 名前なしモジュール
    クラスパス上にあるコンテンツ

このうち、自動モジュールと名前なしモジュールはマイグレーションの過程で使用します。

requiresするのは直接利用しているモジュールのみでよい
monitor.persistence
        ↓
monitor.statistics
        ↓
monitor.observer

このモジュール依存関係の場合、monitor.persistenceはmonitor.statisticsをrequiresすればよく、monitor.observerのrequiresは不要です。 また、monitor.persistenceをコンパイルする場合、monitor.statisticsモジュールが存在すればよく、monitor.observerモジュールは存在しなくても構いません。ただし、実行時にはすべてのモジュールが必要です。

循環参照が生じるモジュール依存関係はエラー