1. 概要

Javaプラットフォームモジュールシステム(JPMS)は、Javaアプリケーションの信頼性を高め、関心の分離を強化し、カプセル化を強化します。 ただし、これはビルドツールではないため、プロジェクトの依存関係を自動的に管理する機能がありません。

もちろん、モジュール化されたアプリケーションでMavenやGradleなどの定評のあるビルドツールを使用できるかどうか疑問に思うかもしれません。

実際、できます! このチュートリアルでは、Javaモジュールを使用してマルチモジュールMavenアプリケーションを作成する方法を学習します。

2. MavenモジュールをJavaモジュールにカプセル化する

モジュール性と依存関係の管理はJavaで相互に排他的な概念ではないため、たとえば JPMS をMavenとシームレスに統合して、両方の長所を活用できます。

標準のマルチモジュールMavenプロジェクトでは、プロジェクトのルートフォルダーの下に配置し、親POM内で宣言することにより、1つ以上の子Mavenモジュールを追加します。 セクション。

次に、各子モジュールのPOMを編集し、標準の<を介してその依存関係を指定します。 groupId> 、< ArtifactId> および< バージョン> 座標。

Mavenのreactorメカニズム(マルチモジュールプロジェクトの処理を担当)は、プロジェクト全体を正しい順序で構築します。

この場合、基本的に同じ設計手法を使用しますが、微妙でありながら基本的なバリエーションが1つあります。モジュール記述子ファイルを追加して、各MavenモジュールをJavaモジュールにラップします。 module-info。java

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を使用しているため、システムには少なくともMaven 3.5.0が必要です。これは、MavenがJava9以降をサポートしているためです

また、少なくともバージョン3.8.0のMavenコンパイラプラグインも必要です。 したがって、MavenCentralのプラグインの最新バージョンを確認してください。

4. 子Mavenモジュール

この時点まで、親POMは子モジュールを宣言していないことに注意してください。

デモプロジェクトは永続層からいくつかのドメインオブジェクトをフェッチするため、4つの子Mavenモジュールを作成します。

  1. entitymodule :単純なドメインクラスが含まれます
  2. daomodule :永続レイヤーにアクセスするために必要なインターフェースを保持します(基本的な DAO コントラクト)
  3. userdaomodule daomoduleのインターフェースの実装が含まれます
  4. mainappmodule :プロジェクトのエントリポイント

4.1. entitymodule Maven Module

次に、基本的なドメインクラスのみを含む最初の子Mavenモジュールを追加しましょう。

プロジェクトのルートディレクトリの下に、 entitymodule / src / main / java / com / baeldung / entity ディレクトリ構造を作成し、 Userclassを追加します。

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. daomoduleMavenモジュール

単純なインターフェースを含む新しいMavenモジュールを作成しましょう。 これは、永続層からジェネリック型をフェッチするための抽象コントラクトを定義するのに便利です。

実際のところ、このインターフェイスを別のJavaモジュールに配置することには非常に説得力のある理由があります。 そうすることで、さまざまなコンテキストで簡単に再利用できる、抽象的で高度に分離されたコントラクトが得られます。コアとなるのは、依存性逆転の原則の代替実装です。これにより、より柔軟な設計が可能になります。

したがって、を作成しましょう dao module / src / main / java / com / baeldung / dao プロジェクトのルートディレクトリの下のディレクトリ構造、およびそれに追加します Dao インターフェース:

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. userdaomoduleMavenモジュール

次に、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を使用しました。 もちろん、たとえば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モジュールにはentitymoduleモジュールと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およびdaomoduleMavenアーティファクトのバージョンを更新する必要があるとしましょう。 モジュール記述子の依存関係を変更することなく、これを簡単に行うことができます。 Mavenは、適切なアーティファクトを含めるように処理します。

同様に、モジュール記述子の「provides..with」ディレクティブを変更することで、モジュールが提供するサービス実装を変更できます。

MavenモジュールとJavaモジュールを一緒に使用すると、多くのメリットが得られます。 前者は自動の集中型依存関係管理の機能をもたらし、後者はモジュール性の本質的な利点を提供します

4.4. mainappmoduleMavenモジュール

さらに、プロジェクトのメインクラスを含む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 インスタンスを使用してマップからそれらをフェッチし、コンソールに表示します。

さらに、モジュールの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を並行して動作させる方法を実践的な方法で学びました。

いつものように、このチュートリアルに示されているすべてのコードサンプルは、GitHubからで入手できます。