
マルチモジュール化は機能のまとまりを明確化し、プロジェクト再利用性やメンテナンス性を高める良い方法です。今回は、Mavenでのマルチモジュール化の方法と、それをSpringプロジェクトに適用する方法を紹介します。
はじめに
マルチモジュール化とは、プロジェクト内に複数のプロジェクトを閉じ込めるようにプロジェクトを構成することです。MavenのPOMには親子関係を示す記述方法があり、それを利用することで複数のプロジェクトに機能分割しつつ、ビルドをまとめて実施することが可能です。当然汎用的な機能を分割しておけば他のプロジェクトに再利用できますし、プロジェクトの肥大化を防げるのでメンテナンスが容易になります。
それでは、Mavenによるマルチモジュール化の方法と、Springプロジェクトへの適用方法を見ていきましょう。
Springプロジェクトのマルチモジュール構成
前提
以下がインストールされている前提で進めます。
- Java10
- Maven3
細かいバージョンは「環境」を参照して下さい。
サンプルのベースのプロジェクトを作る
まずはMavenでベースのプロジェクトを作りましょう。
$ mvn -B archetype:generate \
> -DarchetypeGroupId=org.apache.maven.archetypes \
> -DgroupId=com.example.project \
> -DartifactId=sample-multi-modules-app
マルチモジュール作成方法①IntelliJからモジュール追加する
IntelliJのIDEを使ってモジュールを追加しましょう。
まずIDEで「sample-multi-modules-app」を開き、「src」フォルダを削除します。
続いて、プロジェクトから「New -> Module」を選択します。
「Next」をクリックします。
モジュール名(今回は「core」)を入力して「Next」をクリックします。
「Finish」をクリックすれば完了です。
同様に「main」というモジュールも追加します。
そうすると以下のようになります。2つのモジュールが追加されており、POMファイルが3つになっています。
デフォルトで作成されたPOMファイルは以下のようになっています。
pom.xml(親)
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.project</groupId>
<artifactId>sample-multi-modules-app</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>core</module>
<module>main</module>
</modules>
<name>sample-multi-modules-app</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
pom.xml(coreモジュール)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sample-multi-modules-app</artifactId>
<groupId>com.example.project</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>core</artifactId>
</project>
pom.xml(mainモジュール)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sample-multi-modules-app</artifactId>
<groupId>com.example.project</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>main</artifactId>
</project>
マルチモジュール作成方法②MavenコマンドからGenerateする
もちろん、Mavenコマンドからマルチモジュールを構成することが可能です。
$ cd sample-multi-modules-app2/
$ tree
.
├── pom.xml
└── src
├── main
│ └── java
│ └── com
│ └── example
│ └── project
│ └── App.java
└── test
└── java
└── com
└── example
└── project
└── AppTest.java
$ rm -rf src/
$ tree
.
└── pom.xml
$ vi pom.xml
...
<packaging>pom</packaging>
...
$ mvn -B archetype:generate \
> -DarchetypeGroupId=org.apache.maven.archetypes \
> -DgroupId=com.example.project.core \
> -DartifactId=core
$ mvn -B archetype:generate \
> -DarchetypeGroupId=org.apache.maven.archetypes \
> -DgroupId=com.example.project.main \
> -DartifactId=main
$ tree
.
├── core
│ ├── pom.xml
│ └── src
│ ├── main
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── project
│ │ └── core
│ │ └── App.java
│ └── test
│ └── java
│ └── com
│ └── example
│ └── project
│ └── core
│ └── AppTest.java
├── main
│ ├── pom.xml
│ └── src
│ ├── main
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── project
│ │ └── main
│ │ └── App.java
│ └── test
│ └── java
│ └── com
│ └── example
│ └── project
│ └── main
│ └── AppTest.java
└── pom.xml
ただし、IntelliJと違って自動でPOMファイルをうまく修正してくれないので、手動での修正が多くなります。
サンプルをSpringプロジェクトにする
サンプルを動く形に手直ししましょう。
IDEで以下の構成でファイルを作成します。
$ tree
.
├── core
│ ├── core.iml
│ ├── pom.xml
│ └── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── project
│ │ │ └── core
│ │ │ ├── AppConfig.java
│ │ │ ├── ApplicationServerImpl.java
│ │ │ └── Server.java
│ │ └── resources
│ │ └── logback.xml
│ └── test
│ └── java
├── main
│ ├── main.iml
│ ├── pom.xml
│ └── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── project
│ │ │ └── main
│ │ │ └── Main.java
│ │ └── resources
│ └── test
│ └── java
└── pom.xml
ソースコードは以下になります。マルチモジュール化したことで、POMを親子で構成している点がポイントです。
pom.xml(親)
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.project</groupId>
<artifactId>sample-multi-modules-app</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>core</module>
<module>main</module>
</modules>
<name>sample-multi-modules-app</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>10</java.version>
<spring.version>5.0.7.RELEASE</spring.version>
<logback.version>1.2.3</logback.version>
<lombok-version>1.18.0</lombok-version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok-version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<target>${java.version}</target>
<source>${java.version}</source>
<release>${java.version}</release>
</configuration>
</plugin>
</plugins>
</build>
</project>
pom.xml(coreモジュール)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sample-multi-modules-app</artifactId>
<groupId>com.example.project</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>core</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
logback.xml(coreモジュール)
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%date [%thread] [%-5level] %logger{40} = %message%n</pattern>
</encoder>
</appender>
<logger name="com.example.project" level="DEBUG"/>
<logger name="org.springframework" level="WARN"/>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
Server.java(coreモジュール)
package com.example.project.core;
import lombok.Getter;
public interface Server {
enum Status {
STOPPED("stopped"), RUNNING("running");
@Getter
private String value;
Status(String value) {
this.value = value;
}
}
public void run();
public String status();
public void stop();
}
ApplicationServerImpl.java(coreモジュール)
package com.example.project.core;
import org.springframework.stereotype.Component;
@Component("applicationServer")
public class ApplicationServerImpl implements Server {
private Status status = Status.STOPPED;
public void run() {
status = Status.RUNNING;
}
public String status() {
return status.getValue();
}
public void stop() {
status = Status.STOPPED;
}
}
AppConfig.java(coreモジュール)
package com.example.project.core;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.example.project")
public class AppConfig {
}
pom.xml(mainモジュール)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sample-multi-modules-app</artifactId>
<groupId>com.example.project</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>main</artifactId>
<dependencies>
<dependency>
<groupId>com.example.project</groupId>
<artifactId>core</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
Main.java(mainモジュール)
package com.example.project.main;
import com.example.project.core.AppConfig;
import com.example.project.core.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@Slf4j
public class Main {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
Server server = (Server) ctx.getBean("applicationServer");
server.run();
log.info("Server is {}.", server.status());
server.stop();
log.info("Server is {}.", server.status());
ctx.close();
}
}
実行してみましょう。
$ mvn clean install -pl main -am
$ cd main/
$ mvn exec:java -Dexec.mainClass="com.example.project.main.Main"
2018-07-12 23:07:50,137 [com.example.project.main.Main.main()] [INFO ] com.example.project.main.Main = Server is running.
2018-07-12 23:07:50,141 [com.example.project.main.Main.main()] [INFO ] com.example.project.main.Main = Server is stopped.
正しく動作しました。これでSpringプロジェクトをマルチモジュール化できました。
最後に
いかがでしたか?これでMavenを使ってSpringプロジェクトをマルチモジュール化できるようになりましたね。ほとんどのプロジェクトで有効な方法ですので、実践していきましょう。では。
環境
- JDK: openjdk 10.0.1 2018-04-17
- Maven: Apache Maven 3.5.3
- SpringFramework: 5.0.7.RELEASE