Dependency Manager/Maven
Maven 멀티 모듈 구성방법
by BAYABA
2021. 9. 27.
- 개인 공부 목적으로 작성한 글입니다.
- 아래 출처를 참고하여 작성하였습니다.
목차
- Intro
- 멀티 모듈 사용 이유
- 공통사항
- mvnw, .mvn 제거
- parent 태그에 spring-boot-starter-parent를 사용하는 경우
- parent 태그에 spring-boot-starter-parent를 사용하지 않는 경우
- Create the Library Project (Create a Service Component)
- Create the Application Project (Entry point)
- Write the Application (Entry point)
- 멀티 모듈 실행
1. Intro
- Maven 멀티 모듈 구성 샘플 코드는 아래 링크를 참고하면 됩니다.
- 이 포스팅은 부모-자식 관계 멀티 모듈 구성으로 Application 모듈과 Library 모듈을 만드는 포스팅입니다.
2. 멀티 모듈 사용 이유
- 부모-자식 관계로 멀티 모듈을 사용하면 자식 컴포넌트 간에 공통으로 사용하는 라이브러리는 부모 컴포넌트를 통해서 관리할 수 있습니다.
- 부모-자식 관계로 멀티 모듈을 사용하면 빌드 스크립트 한 줄로 자식 모듈을 전부 빌드할 수 있습니다.
3. 공통사항
- Application 모듈과 Library 모듈에 공통으로 적용되는 내용입니다.
3-1. mvnw, .mvn 제거
- Application과 Library 모듈 모두 부모 모듈이 빌드 될 때 함께 실행되기 때문에 자신의 프로젝트 내에 있는 mvnw와 .mvn은 지워줍니다.
$ rm -rf mvnw* .mvn
$ rm -rf gradlew* gradle
3-2. parent 태그에 spring-boot-starter-parent를 사용하는 경우
- 기본적으로 spring 이니셜라이저를 사용하면 parent 태그에 spring-boot-starter-parent가 붙습니다.
- 하지만 부모 컴포넌트에서 자식 컴포넌트의 일부 의존성을 관리해줄 것이라면 자식 컴포넌트에서는 이걸 사용하면 안 됩니다.
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
</parent>
3-3. parent 태그에 spring-boot-starter-parent를 사용하지 않는 경우
- 사용하지 않는 경우라고 한다면, 자식 컴포넌트에서 parent 태그에 부모 컴포넌트를 사용하는 경우입니다.
- 스프링 부트 사용 시, parent 태그에 spring-boot-starter-parent를 사용하지 않는다면 아래 태그를 사용해서 spring-boot-starter-parent처럼 종속성 관리를 할 수 있습니다.
<parent>
<groupId>org.example</groupId>
<artifactId>multi-module</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
...
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.5.5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
4. Create the Library Project (Create a Service Component)
- Library 모듈(프로젝트)에는 main function이 있는 클래스가 없습니다(응용 프로그램이 아니기 때문에).
- 그러므로 Library 모듈(프로젝트)에 대해 실행 가능한 jar를 빌드하지 않도록 빌드 시스템에 알려야 합니다.
- 기본적으로 Spring Initializr는 실행 가능한 jar로 프로젝트를 빌드합니다.
- Maven에 Library 모듈(프로젝트)에 대해 실행 가능한 jar를 빌드하지 않도록 지시하려면 Spring Initializr에 의해 생성된 pom.xml에서 다음 블록을 제거해야 합니다.
# pom.xml에 아래 태그 제거
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
5. Create the Application Project (Entry point)
- Application 프로젝트는 멀티 모듈의 Entry point로, 다른 프로젝트에서 사용할 수 있도록 서비스를 제공하는 Library 프로젝트를 사용합니다.
- Application 프로젝트에는 Library 프로젝트에 대한 종속성이 있어야 합니다. 그러므로 pom.xml 파일을 수정합니다.
# pom.xml에 아래 태그 추가
<dependency>
<groupId>com.example</groupId>
<artifactId>library</artifactId>
<version>${project.version}</version>
</dependency>
- Application 프로젝트는 main function이 있습니다. 그러므로 Application 프로젝트에 대해 실행 가능한 jar를 빌드하도록 아래 태그는 유지합니다.
# Application Project는 아래 태그가 있어야 합니다.
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
6. Write the Application (Entry point)
- 아래 코드에서 중요한 건 scanBasePackages 부분입니다.
- Application 프로젝트와 Library 프로젝트는 서로 다른 경로에 있으므로 자동 적용되는 ComponentScan으로는 Library 모듈에 있는 빈을 찾을 수 없습니다.
- 위 2번 문제는 두 가지 방법으로 해결이 가능합니다.
- Import it directly with @Import(MyService.class).
- Fetch everything from its package by using @SpringBootApplication(scanBasePackageClasses={}).
- 아래 코드 예시에서는 scanBasePackages를 사용하여 Library 프로젝트의 컴포넌트가 있는 부모 패키지를 스캔합니다.
package com.example.myapp;
import com.example.mylibrary.service.MyService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication(scanBasePackages = "com.example.mylibrary")
@RestController
public class MyAppApplication {
private final MyService myService;
public MyAppApplication(MyService myService) {
this.myService = myService;
}
@GetMapping
public String home() {
return myService.message();
}
public static void main(String[] args) {
SpringApplication.run(MyAppApplication.class, args);
}
}
7. 멀티 모듈 실행
- 아래 한 줄로 멀티 모듈을 모두 빌드하고 실행할 수 있습니다.
- Application과 Library 프로젝트를 모두 maven으로 빌드합니다.
- 그리고 난 후 멀티 모듈의 entry point(main function 존재)인 application 프로젝트를 실행합니다.
$ ./mvnw install && ./mvnw spring-boot:run -pl application
출처
- Spring + Maven Project Parent Child 구조로 만들기 (Multi-Module Project)
- Creating a Multi Module Project
- 3.1. Inheriting the Starter Parent POM
- 3.2. Using Spring Boot without the Parent POM