Javaモジュールを使用したマルチモジュールMavenアプリケーション

1. 概要

link:/java-9-modularity[Java Platform Module System](JPMS)は、信頼性の向上、懸念の分離の向上、Javaアプリケーションへのカプセル化の強化を実現します。 ただし、ビルドツールではないため、*プロジェクトの依存関係を自動的に管理する機能がありません。*
もちろん、https://www.baeldung.com/maven [Maven]やlink:/gradle[Gradle]*などの確立されたビルドツールを使用できるかどうか疑問に思うかもしれません。モジュール化されたアプリケーションで。
実際、できます! このチュートリアルでは、* Javaモジュールを使用してマルチモジュールMavenアプリケーションを作成する方法を学習します*。

2. JavaモジュールでのMavenモジュールのカプセル化

*モジュラリティと依存関係の管理はJavaで相互に排他的な概念ではない*ため、たとえばlink:/new-java-9[JPMS]をMavenとシームレスに統合し、最高の両方の世界。
標準のマルチモジュールMavenプロジェクトでは、プロジェクトのルートフォルダーの下に配置し、_ <modules> _セクション内の親POMで宣言することにより、1つ以上の子Mavenモジュールを追加します。
次に、各子モジュールのPOMを編集し、標準の<__ groupId> __、<__ artifactId> __および<__ version> __座標を介して依存関係を指定します。
マルチモジュールプロジェクトの処理を担当するMavenの_reactor_メカニズムは、プロジェクト全体を正しい順序で構築します。
この場合、基本的には同じ設計方法論を使用しますが、1つの微妙でありながら基本的なバリアントを使用します。

3. 親Mavenモジュール

モジュール性と依存関係の管理がどのように連携するかを示すために、基本的なデモのマルチモジュールMavenプロジェクトを構築します。
コードをシンプルに保つために、ドメインオブジェクトを格納するための基礎となるデータ構造としてプレーン_Map_を使用します。 もちろん、将来的には本格的なリレーショナルデータベースに簡単に切り替えることができます。
まず、親Mavenモジュールを定義することから始めましょう。 これを実現するために、たとえば_multimodulemavenproject_という名前のルートプロジェクトディレクトリを作成し(ただし、それは他のものでもかまいません)、それに親_pom.xml_ファイルを追加します。
<groupId>com.baeldung.multimodulemavenproject</groupId>
<artifactId>multimodulemavenproject</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<name>multimodulemavenproject</name>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
親POMの定義には、注目に値するいくつかの詳細があります。
まず、Java 11を使用しているため、* system __、__には少なくともMaven 3.5.0が必要です。Mavenはそのバージョン以降のJava 9以降をサポートしています*。
また、少なくともlink:/maven-compiler-plugin[Maven compiler plugin]のバージョン3.8.0が必要です。 したがって、https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.apache.maven.plugins%22%20AND%20a%3A%22maven-compilerを必ず確認してください。 -plugin%22 [Maven Centralのプラグインの最新バージョン]。

4. 子Mavenモジュール

ここまで、*親POMは子モジュールを宣言していません*。
デモプロジェクトは永続層からいくつかのドメインオブジェクトを取得するため、4つの子Mavenモジュールを作成します。
  1. entitymodule:単純なドメインクラスが含まれます

  2. daomodule:へのアクセスに必要なインターフェースを保持します
    永続化レイヤー(基本的なDAOコントラクト)

  3. userdaomoduledaomodule’sの実装が含まれます
    インタフェース

  4. mainappmodule:プロジェクトのエントリポイント

* 4.1。 entitymodule Mavenモジュール*

次に、最初の子Mavenモジュールを追加しましょう。これには、基本的なドメインクラスが含まれています。
プロジェクトのルートディレクトリの下に、_entitymodule / src / main / java / com / baeldung / entity_ディレクトリ構造を作成し、_User_クラスを追加しましょう。
public class User {

    private final String name;

    // standard constructor / getter / toString

}
次に、モジュールの_pom.xml_ファイルをインクルードしましょう。
<parent>
    <groupId>com.baeldung.multimodulemavenproject</groupId>
    <artifactId>multimodulemavenproject</artifactId>
    <version>1.0</version>
</parent>

<groupId>com.baeldung.entitymodule</groupId>
<artifactId>entitymodule</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>entitymodule</name>
ご覧のとおり、_Entity_モジュールには他のモジュールへの依存関係はなく、_User_クラスのみが含まれているため、追加のMavenアーティファクトも必要ありません。
ここで、MavenモジュールをJavaモジュールにカプセル化する必要があります*。 これを実現するには、次のモジュール記述子ファイル(_module-info.java_)を_entitymodule / src / main / java_ディレクトリの下に配置します。
module com.baeldung.entitymodule {
    exports com.baeldung.entitymodule;
}
最後に、子Mavenモジュールを親POMに追加しましょう。
<modules>
    <module>entitymodule</module>
</modules>

* 4.2。 daomodule Mavenモジュール*

シンプルなインターフェースを含む新しいMavenモジュールを作成しましょう。 これは、永続層からジェネリック型を取得するための抽象的なコントラクトを定義するのに便利です。
実際、このインターフェイスを別のJavaモジュールに配置する非常に説得力のある理由があります。 *そうすることにより、抽象的で高度に分離されたコントラクトがあり、異なるコンテキストで簡単に再利用できます。*コアでは、これはlink:/java-dependency-の代替実装ですinversion-principle [Dependency Inversion Principle]、より柔軟な設計をもたらします。
したがって、プロジェクトのルートディレクトリの下に_daomodule / src / main / java / com / baeldung / dao_ディレクトリ構造を作成し、それに_Dao <T> _インターフェイスを追加しましょう。
public interface Dao<T> {

    Optional<T> findById(int id);

    List<T> findAll();

}
次に、モジュールの_pom.xml_ファイルを定義しましょう。
<parent>
    // parent coordinates
</parent>

<groupId>com.baeldung.daomodule</groupId>
<artifactId>daomodule</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>daomodule</name>
新しいモジュールは、他のモジュールやアーティファクトも必要としないため、Javaモジュールにまとめます。 _daomodule / src / main / java_ディレクトリの下にモジュール記述子を作成しましょう。
module com.baeldung.daomodule {
    exports com.baeldung.daomodule;
}
最後に、モジュールを親POMに追加しましょう。
<modules>
    <module>entitymodule</module>
    <module>daomodule</module>
</modules>

* 4.3。 userdaomodule Mavenモジュール*

次に、_Dao_インターフェースの実装を保持するMavenモジュールを定義しましょう。
プロジェクトのルートディレクトリの下に、_userdaomodule / src / main / java / com / baeldung / userdao_ディレクトリ構造を作成し、次の_UserDao_クラスを追加します。
public class UserDao implements Dao<User> {

    private final Map<Integer, User> users;

    // standard constructor

    @Override
    public Optional<User> findById(int id) {
        return Optional.ofNullable(users.get(id));
    }

    @Override
    public List<User> findAll() {
        return new ArrayList<>(users.values());
    }
}
*簡単に言えば、_UserDao_クラスは、永続層から_User_オブジェクトを取得できる基本的なAPIを提供します。*
物事を単純にするために、ドメインオブジェクトを永続化するためのバッキングデータ構造として_Map_を使用しました。 もちろん、たとえばlink:/hibernate-entitymanager[Hibernateのエンティティマネージャー]を使用するより完全な実装を提供することは可能です。
それでは、MavenモジュールのPOMを定義しましょう。
<parent>
    // parent coordinates
</parent>

<groupId>com.baeldung.userdaomodule</groupId>
<artifactId>userdaomodule</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>userdaomodule</name>

<dependencies>
    <dependency>
        <groupId>com.baeldung.entitymodule</groupId>
        <artifactId>entitymodule</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>com.baeldung.daomodule</groupId>
        <artifactId>daomodule</artifactId>
        <version>1.0</version>
    </dependency>
</dependencies>
この場合、_userdaomodule_モジュールはe__ntitymodule__および_daomodule_モジュールを必要とするため、状況はわずかに異なります。 そのため、_pom.xml_ファイルに依存関係として追加しました。
このMavenモジュールをJavaモジュールにカプセル化する必要があります。 _userdaomodule / src / main / java_ディレクトリの下に次のモジュール記述子を追加しましょう。
module com.baeldung.userdaomodule {
    requires com.baeldung.entitymodule;
    requires com.baeldung.daomodule;
    provides com.baeldung.daomodule.Dao with com.baeldung.userdaomodule.UserDao;
    exports com.baeldung.userdaomodule;
}
最後に、この新しいモジュールを親POMに追加する必要があります。
<modules>
    <module>entitymodule</module>
    <module>daomodule</module>
    <module>userdaomodule</module>
</modules>
高レベルのビューからは、* _ pom.xml_ファイルとモジュール記述子が異なる役割を果たしていることが簡単にわかります*。 それでも、お互いをうまく補完します。
e__ntitymodule__および_daomodule_ Mavenアーティファクトのバージョンを更新する必要があるとしましょう。 モジュール記述子の依存関係を変更することなく、これを簡単に行うことができます。 Mavenが適切なアーティファクトを含めてくれます。
同様に、モジュール記述子の_“ provides..with” _ディレクティブを変更することにより、モジュールが提供するサービス実装を変更できます。
MavenとJavaモジュールを一緒に使用すると、多くの利益が得られます。 *前者は自動化された一元化された依存関係管理の機能を提供し、後者はモジュール性の本質的な利点を提供します*。

* 4.4。 mainappmodule Mavenモジュール*

さらに、プロジェクトのメインクラスを含むMavenモジュールを定義する必要があります。
前に行ったように、ルートディレクトリの下に_mainappmodule / src / main / java / mainapp_ディレクトリ構造を作成し、次の_Application_クラスを追加します。
public class Application {

    public static void main(String[] args) {
        Map<Integer, User> users = new HashMap<>();
        users.put(1, new User("Julie"));
        users.put(2, new User("David"));
        Dao userDao = new UserDao(users);
        userDao.findAll().forEach(System.out::println);
    }
}
_Application_クラスの_main()_メソッドは非常に簡単です。 まず、_HashMap_にいくつかの_User_オブジェクトを追加します。 次に、_UserDao_インスタンスを使用して_Map、_からそれらを取得し、コンソールに表示します。
さらに、モジュールの_pom.xml_ファイルも定義する必要があります。
<parent>
    // parent coordinates
</parent>

<groupId>com.baeldung.mainappmodule</groupId>
<artifactId>mainappmodule</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>mainappmodule</name>

<dependencies>
    <dependency>
        <groupId>com.baeldung.entitymodule</groupId>
         <artifactId>entitymodule</artifactId>
         <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>com.baeldung.daomodule</groupId>
        <artifactId>daomodule</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>com.baeldung.userdaomodule</groupId>
        <artifactId>userdaomodule</artifactId>
        <version>1.0</version>
    </dependency>
</dependencies>
モジュールの依存関係は一目瞭然です。 したがって、モジュールをJavaモジュール内に配置するだけです。 したがって、_mainappmodule / src / main / java_ディレクトリ構造の下に、モジュール記述子を含めましょう。
module com.baeldung.mainappmodule {
    requires com.baeldung.entitypmodule;
    requires com.baeldung.userdaopmodule;
    requires com.baeldung.daopmodule;
    uses com.baeldung.daopmodule.Dao;
}
最後に、このモジュールを親POMに追加しましょう。
<modules>
    <module>entitymodule</module>
    <module>daomodule</module>
    <module>userdaomodule</module>
    <module>mainappmodule</module>
</modules>
すべての子Mavenモジュールがすでに配置されており、Javaモジュールにきちんとカプセル化されているため、プロジェクトの構造は次のようになります。
multimodulemavenproject (the root directory)
pom.xml
|-- entitymodule
    |-- src
        |-- main
            | -- java
            module-info.java
            |-- com
                |-- baeldung
                    |-- entity
                    User.class
    pom.xml
|-- daomodule
    |-- src
        |-- main
            | -- java
            module-info.java
            |-- com
                |-- baeldung
                    |-- dao
                    Dao.class
    pom.xml
|-- userdaomodule
    |-- src
        |-- main
            | -- java
            module-info.java
            |-- com
                |-- baeldung
                    |-- userdao
                    UserDao.class
    pom.xml
|-- mainappmodule
    |-- src
        |-- main
            | -- java
            module-info.java
            |-- com
                |-- baeldung
                    |-- mainapp
                    Application.class
    pom.xml

5. アプリケーションの実行

最後に、IDE内またはコンソールからアプリケーションを実行しましょう。
予想どおり、アプリケーションの起動時に、いくつかの_User_オブジェクトがコンソールに出力されます。
User{name=Julie}
User{name=David}

6. 結論

このチュートリアルでは、Javaモジュールを使用する基本的なマルチモジュールMavenプロジェクトの開発において、MavenとJPMSを並行して動作させる方法を実用的な方法で学びました*。
いつものように、このチュートリアルに示されているすべてのコードサンプルはhttps://github.com/eugenp/tutorials/tree/master/core-java-modules/multimodulemavenproject[over on GitHub]で入手できます。