1前書き


Project Jigsaw

は、2つの側面を目的とした新しい機能を備えた包括的なプロジェクトです。

  • Java言語でのモジュールシステムの紹介

  • およびJDKソースとJavaランタイムでのその実装

この記事では、Jigsawプロジェクトとその機能を紹介し、最後に簡単なモジュール式アプリケーションでまとめます。


2モジュール性

簡単に言えば、モジュール性は私達が達成するのを助ける設計原則です

  • コンポーネント間の疎結合

  • コンポーネント間の明確な契約と依存関係

  • 強力なカプセル化を使った隠された実装


2.1. モジュラリティの単位

モジュール化の単位は何ですか? Javaの世界、特にOSGiでは、JARはモジュール化の単位と見なされていました。

JARは関連コンポーネントをグループ化するのに役立ちましたが、いくつかの制限があります。

JAR間の明示的な契約と依存関係

JAR内の要素の弱いカプセル化


2.2. JAR地獄

JARには別の問題がありました – JAR地獄です。クラスパス上にあるJARの複数のバージョンが原因で、

ClassLoader

がJARから最初に見つかったクラスをロードすることになり、非常に予期しない結果になりました。

クラスパスを使用するJVMのもう1つの問題は、アプリケーションのコンパイルは成功するということですが、実行時にクラスパスにJARがないため、アプリケーションは

ClassNotFoundException

で実行時に失敗します。


2.3. 新しいモジュール単位

モジュール化の単位としてJARを使用する場合、これらすべての制限があるため、Java言語の作成者はモジュールと呼ばれる言語で新しい構成を思い付きました。そしてこれで、Java用に計画された全く新しいモジュラーシステムがあります。


3プロジェクトジグソーパズル

このプロジェクトの主な動機は次のとおりです。


  • 言語用のモジュールシステムを作成

    – の下で実装


http://openjdk.java.net/jeps/261



JDKソースに適用** – 以下に実装


http://openjdk.java.net/jeps/201



JDK


ライブラリをモジュール化** – の下で実装


http://openjdk.java.net/jeps/200



モジュール性をサポートするようにランタイムを更新** – の下で実装


http://openjdk.java.net/jeps/220



JDKのモジュールのサブセットを使用して小さなランタイムを作成できる

もう1つの重要なイニシアチブは、JDKの内部API、

sun。**

パッケージの下にいるもの、およびその他の非標準APIをカプセル化することです。これらのAPIは、一般に使用されることを意図したものではなく、保守される予定もありませんでした。しかし、これらのAPIの能力により、Java開発者はさまざまなライブラリ、フレームワーク、およびツールの開発にそれらを活用することができました。いくつかの内部APIに代わるものがあり、その他は内部モジュールに移動しました。


4モジュール化のための新しいツール


  • jdeps

    – コードベースの分析に役立ちます。

JDK APIおよびサードパーティJARへの依存関係それはまた言及します
JDK APIが見つかるモジュールの名前。これにより簡単になります
コードベースのモジュール化


jdeprscan ** – コードベースの分析に役立ちます。

廃止予定のAPI


jlink ** – を組み合わせることで、より小さなランタイムを作成するのに役立ちます。

アプリケーションとJDKのモジュール


jmod ** – jmodファイルを扱うのに役立ちます。 jmodは新しいフォーマットです。

モジュールの梱包この形式では、ネイティブコード、設定ファイル、およびJARファイルに収まらないその他のデータを含めることができます。


5モジュールシステムアーキテクチャ

言語で実装されたモジュールシステムは、パッケージと同じように、これらをトップレベルの構成要素としてサポートします。開発者は自分のコードをモジュールに編成し、それぞれのモジュール定義ファイルでそれらの間の依存関係を宣言できます。


module-info.java

という名前のモジュール定義ファイルには、次のものが含まれています。

  • その名前

  • 公開されているパッケージ

  • それが依存するモジュール

  • 消費するサービス

  • 提供するサービスの実装

上記のリストの最後の2つの項目は、一般的には使用されていません。

java.util.ServiceLoader

インターフェースを介してサービスが提供および消費されている場合にのみ使用されます。

モジュールの一般的な構造は次のようになります。

src
 |----com.baeldung.reader
 |     |----module-info.java
 |     |----com
 |          |----baeldung
 |               |----reader
 |                    |----Test.java
 |----com.baeldung.writer
      |----module-info.java
           |----com
                |----baeldung
                     |----writer
                          |----AnotherTest.java

上の図は、

com.baeldung.reader



com.baeldung.writer

の2つのモジュールを定義しています。それぞれの定義は

module-info.java

で指定されており、コードファイルはそれぞれ

com/baeldung/reader

および

com/baeldung/writer

の下に置かれています。

5.1. モジュール定義の用語

いくつかの用語を見てみましょう。モジュールを定義しながら(つまり、__module-info.java内で)使用します。



  • module


    :モジュール定義ファイルはこのキーワードで始まります

その名前と定義が続きます




require ** :は依存しているモジュールを示すために使われます。モジュール

このキーワードの後に​​名前を指定する必要があります




推移的** :は

requires

キーワードの後に​​指定されます。これの意味は


を定義しているモジュールに依存するすべてのモジュールは推移的であること
<モジュール名>

は、<

モジュール名>


への暗黙の依存関係を取得します。



exports ** __:はモジュール内のパッケージを示すのに使われます

公に利用可能です。この後にパッケージ名を指定する必要があります
キーワード




opens ** :はアクセス可能なパッケージのみを示す

実行時に、Reflection APIを介したイントロスペクションにも使用できます。
これはSpringやHibernateのようなライブラリにとって非常に重要です。
Reflection APIに依存します。

opens

は、モジュールレベルでも使えます。
この場合、モジュール全体が実行時にアクセス可能になります。




uses ** :はこのモジュールが持つサービスインタフェースを示すために使われます。

使っています;型名、すなわち完全なクラス/インタフェース名は
このキーワードの後に​​指定



は..

** を付けて提供します。


provides

キーワードの後に​​識別されるサービスインタフェースの、

with

キーワードの後に​​識別される実装

6.シンプルなモジュラーアプリケーション

下の図に示すように、モジュールとその依存関係を含む単純なモジュール式アプリケーションを作成しましょう。

リンク:/uploads/projectjigsaw

baeldun

modulegraph-279×300.png%20279w[]


com.baeldung.student.model

はルートモジュールです。次のプロパティを含むモデルクラス

com.baeldung.student.model.Student

を定義します。

public class Student {
    private String registrationId;
   //other relevant fields, getters and setters
}

それは

com.baeldung.student.model

パッケージで定義された型を持つ他のモジュールを提供します。これは、

module-info.java

ファイルで定義することによって実現されます。

module com.baeldung.student.model {
    exports com.baeldung.student.model;
}


com.baeldung.student.service

モジュールは抽象CRUD操作を持つインターフェース

com.baeldung.student.service.StudentService

を提供します。

public interface StudentService {
    public String create(Student student);
    public Student read(String registrationId);
    public Student update(Student student);
    public String delete(String registrationId);
}

これは

com.baeldung.student.model

モジュールに依存しており、

com.baeldung.student.service

パッケージで定義されている型を他のモジュールで使用できるようにします。

module com.baeldung.student.service {
    requires transitive com.baeldung.student.model;
    exports com.baeldung.student.service;
}

上記のモジュールの実装

com.baeldung.student.service.dbimpl.StudentDbService

を提供する別のモジュール

com.baeldung.student.service.dbimpl

を提供します。

public class StudentDbService implements StudentService {

    public String create(Student student) {
       //Creating student in DB
        return student.getRegistrationId();
    }

    public Student read(String registrationId) {
       //Reading student from DB
        return new Student();
    }

    public Student update(Student student) {
       //Updating sutdent in DB
        return student;
    }

    public String delete(String registrationId) {
       //Deleting sutdent in DB
        return registrationId;
    }
}

それは直接

com.baeldung.student.service

に依存し、他動的に

com.baeldung.student.model

に依存し、その定義は次のようになります。

module com.baeldung.student.service.dbimpl {
    requires transitive com.baeldung.student.service;
    requires java.logging;
    exports com.baeldung.student.service.dbimpl;
}

最後のモジュールはクライアントモジュールです。これはサービス実装モジュール

com.baeldung.student.service.dbimpl

を利用してその操作を実行します。

public class StudentClient {

    public static void main(String[]args) {
        StudentService service = new StudentDbService();
        service.create(new Student());
        service.read("17SS0001");
        service.update(new Student());
        service.delete("17SS0001");
    }
}

そしてその定義は次のとおりです。

module com.baeldung.student.client {
    requires com.baeldung.student.service.dbimpl;
}

7.サンプルのコンパイルと実行

WindowsとUnixプラットフォーム用に上記のモジュールをコンパイルして実行するためのスクリプトを用意しました。これらは

core-java-9

プロジェクトhttps://github.com/eugenp/tutorials/tree/master/core-java-9[ここ]にあります。 Windowsプラットフォームでの実行順序は次のとおりです。

  1. 学生モデルのコンパイル

  2. 学生サービス編集

  3. コンパイル学生サービスdbimpl

  4. 学生クライアントのコンパイル

  5. 実行学生クライアント

Linuxプラットフォームでの実行順序はとても簡単です。

  1. コンパイルモジュール

  2. 実行学生クライアント

上記のスクリプトでは、次の2つのコマンドライン引数が紹介されます。


  • – モジュールソースパス


  • – モジュールパス

Java 9はクラスパスの概念を廃止し、代わりにモジュールパスを導入しています。このパスは、モジュールが検出される場所です。

これを設定するには、コマンドライン引数

– module-path

を使用します。

一度に複数のモジュールをコンパイルするために、

-module-source-path

を使用します。この引数は、モジュールのソースコードの場所を指定するために使用されます。


8 JDKソースに適用されるモジュールシステム

すべてのJDKインストールには

src.zip

が付属しています。このアーカイブには、JDK Java APIのコードベースが含まれています。アーカイブを解凍すると、

java

で始まるフォルダ、

javafx

で始まるフォルダ、

jdk.

で始まるフォルダが複数存在します。各フォルダはモジュールを表します。

リンク:/uploads/jdk9-src-170×300.png%20170w[]


java

で始まるモジュールはJDKモジュール、

javafx

で始まるモジュールはJavaFXモジュール、そして

jdk

で始まるモジュールはJDKツールモジュールです。

すべてのJDKモジュールとすべてのユーザー定義モジュールは、

java.base

モジュールに暗黙的に依存しています。

java.base

モジュールには、Utils、Collections、IO、Concurrencyなどの一般的に使用されるJDK APIが含まれています。 JDKモジュールの依存グラフは次のとおりです。

リンク:/uploads/jdk-tr1-1024×350.png%201024w[]

また、JDKモジュールの定義を調べて、

module-info.java

でそれらを定義するための構文を理解することもできます。


9結論

この記事では、単純なモジュール式アプリケーションの作成、コンパイル、および実行について説明しました。また、JDKのソースコードがどのようにモジュール化されているのかも見ました。

jlinkや他の機能の中でも特にモジュール式のjarを作成するなど、リンカツールを使用して小さなランタイムを作成するような、もっとおもしろい機能がいくつかあります。今後の記事で、これらの機能について詳しく説明します。

Project Jigsawは大きな変化です。開発者のエコシステム、特にツールやライブラリの作成者にとって、それがどのように受け入れられるかを見守る必要があります。

この記事で使われているコードはhttps://github.com/eugenp/tutorials/tree/master/core-java-9[GitHubに載っています]。