【Java】モジュールについて

## モジュールとは
モジュールはパッケージの上位に位置付けられ、パッケージをグループ化するものである。主なモジュールの目的は以下。
* **信頼性の高い構成**
モジュールの依存性を明示的に宣言できる
* **強力なカプセル化**
明示的にモジュールをエクスポートした場合のみ、そのモジュールへのアクセスが可能になる
* **スケーラブルなjavaプラットフォーム**
基本的なAPIもモジュール分割されており、必要なモジュールで構成されたJava実行環境を作ることが可能
* **プラットフォームの整合性向上**
内部APIをカプセル化にしたり、アプリケーションを非公開にできる
* **パフォーマンス向上**
必要なクラスが特定のモジュールにしかないことでさらにパフォーマンス向上が見込める

## JDKをモジュール化する理由
* **アプリケーションモジュールとJDKのモジュールのリンクが容易に構築できる**
アプリケーションのモジュールを作る際にそのアプリケーションが使うJREのモジュールを含めると、Javaがインストールされていなくてもアプリケーションを実行できるようになる。この時、JREで提供されている標準クラスライブラリの全てではなく、必要なモジュールだけを指定して含めることができる。JREのモジュールを含めるには**jliinkコマンド**を使う。

* **セキュリティとメンテナンス性が向上する**
公開するパッケージを指定し、それ以外を非公開とすることで、外部のパッケージからのアクセス制御が可能となる。

:::note info
**堅牢性とは**
エラーになるような操作や事態が発生しても、ユーザーに影響を与えない能力のこと。よく問題に出てくるので覚える。
:::

## モジュールの定義
以下のようにフォルダを切って、各ファイルを配置する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521217/cde1c957-f510-564f-04b0-42d7791a1490.png)

module-info.javaはモジュールをを定義するファイルである。
```ruby:Java(Main.java)
package com.seshop.sample.main;

public class Main{
	public static void main(String[] args){
		System.out.println("Module System");
	}
}	
```

```ruby:Java(module-info.java)
    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
```

これにより、フォルダ構成は以下のようになった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521217/d982406c-e822-aff4-0aaf-1a10535cf51c.png)

## モジュールの情報を参照
モジュールの情報を参照したい場合は以下のコマンドを使用する。
コマンド
```
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オプション```を使う