본문 바로가기
Dependency Manager/Maven

Maven 멀티 모듈 구성방법

by BAYABA 2021. 9. 27.
  1. 개인 공부 목적으로 작성한 글입니다.
  2. 아래 출처를 참고하여 작성하였습니다.

목차

  1. Intro
  2. 멀티 모듈 사용 이유
  3. 공통사항
  • mvnw, .mvn 제거
  • parent 태그에 spring-boot-starter-parent를 사용하는 경우
  • parent 태그에 spring-boot-starter-parent를 사용하지 않는 경우
  1. Create the Library Project (Create a Service Component)
  2. Create the Application Project (Entry point)
  3. Write the Application (Entry point)
  4. 멀티 모듈 실행

1. Intro

  1. Maven 멀티 모듈 구성 샘플 코드는 아래 링크를 참고하면 됩니다.
  1. 이 포스팅은 부모-자식 관계 멀티 모듈 구성으로 Application 모듈과 Library 모듈을 만드는 포스팅입니다.

2. 멀티 모듈 사용 이유

  • 부모-자식 관계로 멀티 모듈을 사용하면 자식 컴포넌트 간에 공통으로 사용하는 라이브러리는 부모 컴포넌트를 통해서 관리할 수 있습니다.
  • 부모-자식 관계로 멀티 모듈을 사용하면 빌드 스크립트 한 줄로 자식 모듈을 전부 빌드할 수 있습니다.

3. 공통사항

  1. Application 모듈과 Library 모듈에 공통으로 적용되는 내용입니다.

3-1. mvnw, .mvn 제거

  1. Application과 Library 모듈 모두 부모 모듈이 빌드 될 때 함께 실행되기 때문에 자신의 프로젝트 내에 있는 mvnw와 .mvn은 지워줍니다.
$ rm -rf mvnw* .mvn
$ rm -rf gradlew* gradle

3-2. parent 태그에 spring-boot-starter-parent를 사용하는 경우

  1. 기본적으로 spring 이니셜라이저를 사용하면 parent 태그에 spring-boot-starter-parent가 붙습니다.
  2. 하지만 부모 컴포넌트에서 자식 컴포넌트의 일부 의존성을 관리해줄 것이라면 자식 컴포넌트에서는 이걸 사용하면 안 됩니다.
<!-- 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를 사용하지 않는 경우

  1. 사용하지 않는 경우라고 한다면, 자식 컴포넌트에서 parent 태그에 부모 컴포넌트를 사용하는 경우입니다.
  2. 스프링 부트 사용 시, 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)

  1. Library 모듈(프로젝트)에는 main function이 있는 클래스가 없습니다(응용 프로그램이 아니기 때문에).
  2. 그러므로 Library 모듈(프로젝트)에 대해 실행 가능한 jar를 빌드하지 않도록 빌드 시스템에 알려야 합니다.
  • 기본적으로 Spring Initializr는 실행 가능한 jar로 프로젝트를 빌드합니다.
  1. 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)

  1. Application 프로젝트는 멀티 모듈의 Entry point로, 다른 프로젝트에서 사용할 수 있도록 서비스를 제공하는 Library 프로젝트를 사용합니다.
  2. Application 프로젝트에는 Library 프로젝트에 대한 종속성이 있어야 합니다. 그러므로 pom.xml 파일을 수정합니다.
# pom.xml에 아래 태그 추가

<dependency>
  <groupId>com.example</groupId>
  <artifactId>library</artifactId>
  <version>${project.version}</version>
</dependency>

  1. 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)

  1. 아래 코드에서 중요한 건 scanBasePackages 부분입니다.
  2. Application 프로젝트와 Library 프로젝트는 서로 다른 경로에 있으므로 자동 적용되는 ComponentScan으로는 Library 모듈에 있는 빈을 찾을 수 없습니다.
  3. 위 2번 문제는 두 가지 방법으로 해결이 가능합니다.
  • Import it directly with @Import(MyService.class).
  • Fetch everything from its package by using @SpringBootApplication(scanBasePackageClasses={}).
  1. 아래 코드 예시에서는 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. 멀티 모듈 실행

  1. 아래 한 줄로 멀티 모듈을 모두 빌드하고 실행할 수 있습니다.
  • Application과 Library 프로젝트를 모두 maven으로 빌드합니다.
  • 그리고 난 후 멀티 모듈의 entry point(main function 존재)인 application 프로젝트를 실행합니다.
$ ./mvnw install && ./mvnw spring-boot:run -pl application

출처

  1. Spring + Maven Project Parent Child 구조로 만들기 (Multi-Module Project)
  2. Creating a Multi Module Project
  3. 3.1. Inheriting the Starter Parent POM
  4. 3.2. Using Spring Boot without the Parent POM

'Dependency Manager > Maven' 카테고리의 다른 글

maven-surefire-plugin:2.18.1:test failed  (0) 2021.10.11
spring-boot-maven-plugin  (0) 2021.09.28
Maven Wrapper 사용법  (0) 2021.09.26
[Tag] dependencyManagement  (0) 2021.09.16