モジュールとは
モジュールはパッケージの上位に位置付けられ、パッケージをグループ化するものである。主なモジュールの目的は以下。
-
信頼性の高い構成
モジュールの依存性を明示的に宣言できる -
強力なカプセル化
明示的にモジュールをエクスポートした場合のみ、そのモジュールへのアクセスが可能になる -
スケーラブルなjavaプラットフォーム
基本的なAPIもモジュール分割されており、必要なモジュールで構成されたJava実行環境を作ることが可能 -
プラットフォームの整合性向上
内部APIをカプセル化にしたり、アプリケーションを非公開にできる -
パフォーマンス向上
必要なクラスが特定のモジュールにしかないことでさらにパフォーマンス向上が見込める
JDKをモジュール化する理由
-
アプリケーションモジュールとJDKのモジュールのリンクが容易に構築できる
アプリケーションのモジュールを作る際にそのアプリケーションが使うJREのモジュールを含めると、Javaがインストールされていなくてもアプリケーションを実行できるようになる。この時、JREで提供されている標準クラスライブラリの全てではなく、必要なモジュールだけを指定して含めることができる。JREのモジュールを含めるにはjliinkコマンドを使う。 -
セキュリティとメンテナンス性が向上する
公開するパッケージを指定し、それ以外を非公開とすることで、外部のパッケージからのアクセス制御が可能となる。
堅牢性とは
エラーになるような操作や事態が発生しても、ユーザーに影響を与えない能力のこと。よく問題に出てくるので覚える。
モジュールの定義
以下のようにフォルダを切って、各ファイルを配置する
module-info.javaはモジュールをを定義するファイルである。
package com.seshop.sample.main;
public class Main{
public static void main(String[] args){
System.out.println("Module System");
}
}
module com.seshop.sample{
requires java.base;
}
モジュールのコンパイル
カレントディレクトリをまずクラスファイル格納先のcom.seshop.sampleにしておく。
それからjava -d コマンドを使用してコンパイルを実施する。コンパイル対象は2つあるため、間にスペースを入れて実行する。この時相対パスでコンパイル対象を指定する。
モジュールのコンパイルコマンド
javac -d <クラスファイルの生成場所> <コンパイル対象のソースファイル
実際のコマンド
~\module>cd com.seshop.sample
~\module\com.seshop.sample>javac -d . ..\src\module-info.java ..\src\Main.java
これにより、フォルダ構成は以下のようになった。
モジュールの情報を参照
モジュールの情報を参照したい場合は以下のコマンドを使用する。
コマンド
java --module-path <モジュールの格納場所> --describe-module
jmod describe
実際のコマンド
~\module\com.seshop.sample>java --module-path . --describe-module com.seshop.sample
com.seshop.sample file:~/module/com.seshop.sample/./
requires java.base
contains com.seshop.sample.main
ここではモジュールの場所・依存モジュール・含まれるパッケージについて表示されている。
モジュールの実行
コマンド
java --module-path(-p) <モジュールの格納場所> --module(-m) <実行するソースファイル名>
ソースファイル名はパッケージを含めた完全修飾名で入力する。
実際のコマンド
~\module>java --module-path . --module com.seshop.sample/com.seshop.sample.main.Main
Module System
実行できることを確認できた。
モジュールの依存関係を調べる
jdeps <ソースファイル名>
プログラム実行時に依存するモジュールがどのように探されているか表示
コマンド
>java --module-path <モジュールの格納場所> --show-module-resolution --module(-m) <実行するソースファイル名>
実際のコマンド
~\module\src>java --module-path . --show-module-resolution com.seshop.sample/com.seshop.sample.main.Main
root jdk.management.jfr jrt:/jdk.management.jfr
root java.sql jrt:/java.sql
root java.rmi jrt:/java.rmi
root jdk.jdi jrt:/jdk.jdi
・・・
モジュールグラフ
モジュールの依存関係をグラフしたものを、モジュールグラフという。例えば以下のコマンドを実行して、Mainクラスの依存関係の状態を確認する。
名前付きモジュール
独自にモジュール名を持つ。
無名モジュール
クラスパス上に存在し、モジュール名を持たないモジュールのこと。これは以下の挙動を示す。
- 全てのパッケージをexportsする
- モジュールパス上の全てのモジュールをrequiresする
- module-info.javaは持たない
- モジュールパスではなくクラスパスに配置されたJarファイルのクラスやパッケージは、無名モジュール(Unnamed Module)と呼ばれるモジュールに所属するようになる
自動モジュール
モジュールパス上に存在し、モジュール名を持たないモジュール。これは以下の挙動を示す。
- 全てのパッケージをexportsする
- モジュールパス上の全てのモジュールをrequiresする(モジュールパス上の全てのモジュールを利用可能)
- module-info.javaは持たない
- module-info.java によるモジュール定義を持たない形式のJarファイルがモジュールパス上に配置された場合、自動的にモジュールとして扱われる
- モジュールパスに配置された非モジュール化JARファイルとして扱われる
--add-exportsオプション
一時的に公開するパッケージを追加できる。ただ、本来はmodule-info.javaに記述することなので推奨はされない。
まとめ
- モジュールとはパッケージをまとめたもので、アクセス制御などを行う
- module-info.javaはモジュールをを定義するファイル
- モジュールをコンパイルするコマンドは
javac -d <クラスファイルの生成場所> <コンパイル対象のソースファイル
- モジュールの情報を参照するコマンドは
java --module-path <モジュールの格納場所> --describe-module
とjmod describe
- モジュールを実行するコマンドは
java --module-path(-p) <モジュールの格納場所> --module(-m) <実行するソースファイル名>
- モジュールの依存関係を調べるコマンドは
jdeps <ソースファイル名>
- 依存するモジュールがどのように探されているか表示するコマンドは
java --module-path <モジュールの格納場所> --show-module-resolution --module(-m) <実行するソースファイル名>
- モジュールグラフはモジュールの依存関係をグラフしたもの
- 名前付きモジュールと無名モジュールと自動モジュールが存在する
- 一時的に公開するパッケージを追加する場合は
--add-exportsオプション
を使う