본문 바로가기
spring

[SpringBoot] Maven Multi-Module Project 생성

by moonsiri 2021. 2. 18.
728x90
반응형

multi-module 가이드를 참조하여 Spring Boot로 멀티 모듈 프로젝트를 생성하는 스터디를 해보겠습니다.

 

멀티 모듈 프로젝트?

멀티 모듈 프로젝트는 기존의 단일 프로젝트를 프로젝트 안의 모듈로서 가질 수 있는 구조를 제공합니다.

장단점

장점

  • 재사용, 공유 할 수 있다
  • 빌드를 쉽게 할 수 있다
  • 변경으로 인한 영향 최소화가 가능하다
  • 의존성을 최소화한다.

 

 

목표

재사용 가능한 라이브러리를 생성하여 해당 라이브러리를 사용하여 "Hello, World" 메시지를 리턴하는 api 애플리케이션 빌드

 

 

 

환경

  • Spring Boot 2.4.2
  • Maven
  • IntelliJ
  • openjdk 11

 

 

 

프로젝트 생성

우선 스프링 부트 프로젝트 생성해봅니다.

File > New > Project... > Spring Initializr
maven project로 multimodule project 생성
spring web dependency 추가

 

 

모듈 생성

그다음 모듈을 생성하겠습니다.

File > New > Module... > Maven
api, service, core 모듈 생성

위와 같은 방법으로 "api", "service", "core"라는 모듈 세 개를 생성합니다.

 

 

프로젝트 생성이 완료되면, 최상위 pom.xml (multimodule) modules 하위에 추가한 모듈을 확인할 수 있습니다.

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <packaging>pom</packaging>
    
    <groupId>com.moonsiri</groupId>
    <artifactId>multimodule</artifactId>
    <version>0.0.1</version>
    
    <name>multi module</name>
    <description>multi module project</description>
    
    <modules>
        <module>api</module>
        <module>core</module>
        <module>service</module>
    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <repositories>
        <repository>
            <id>MOONSIRI-REPOSITORY</id>
            <url>...</url>
        </repository>

        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>

    <!-- deploy repo setting -->
    <distributionManagement>
        <repository>
            <id>MOONSIRI-REPOSITORY</id>
            <name>MOONSIRI-REPOSITORY</name>
            <url>...</url>
        </repository>
    </distributionManagement>

    <properties>
        <encoding>UTF-8</encoding>
        <java.version>11</java.version>
    </properties>

    <dependencies>
    	<!-- 공통으로 사용하는 dependency 추가 -->
    </dependencies>

</project>

 

 

multi-module (core, service, api)

 

 

core 모듈

core 모듈은 "jar"로 패키징 되어 다른 곳에서 사용되어야 하기 때문에 pom.xml(core)에 packaging 설정을 해줍니다.

<?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">
    <modelVersion>4.0.0</modelVersion>
    <packaging>jar</packaging> <!-- jar로 packaging -->
    
    <!-- 상위 pom.xml 사용 -->
    <parent>
        <groupId>com.moonsiri</groupId>
        <artifactId>multimodule</artifactId>
        <version>0.0.1</version>
    </parent>

    <groupId>com.moonsiri.multimodule</groupId>
    <artifactId>core</artifactId>
    <version>0.0.1</version>

    <distributionManagement>
        <repository>
            <id>저장소ID</id>
            <name>저장소명</name>
            <url>저장소URL</url>
        </repository>
    </distributionManagement>

</project>

 

api 모듈에서 조회할 메시지를 설정 후 properties configuration을 생성합니다.

service.message=Hello, World
package com.moonsiri.multimodule.config;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("service")
public class ServiceProperties {

    private String message; // service.message

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

 

maven deploy로 라이브러리를 레파지토리에 deploy합니다.

 

service 모듈

service 모듈은 core 모듈을 사용하기 위해 dependency에 추가를 해줍니다.

<?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">
    <modelVersion>4.0.0</modelVersion>
    <packaging>jar</packaging> <!-- jar로 packaging -->
    
    <!-- 상위 pom.xml 사용 -->
    <parent>
        <groupId>com.moonsiri</groupId>
        <artifactId>multimodule</artifactId>
        <version>0.0.1</version>
    </parent>
    
    <groupId>com.moonsiri.multimodule</groupId>
    <artifactId>service</artifactId>
    <version>0.0.1</version>

    <dependencies>

        <!-- core 모듈 사용 -->
        <dependency>
            <groupId>com.moonsiri.multimodule</groupId>
            <artifactId>core</artifactId>
            <version>0.0.1</version>
        </dependency>
    </dependencies>

    <!-- source 공개 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>3.1.0</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    
</project>

 

core 모듈의 ServiceProperties로 메시지를 조회하는 Service를 생성합니다.

package com.moonsiri.multimodule.service;

import com.moonsiri.multimodule.config.ServiceProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;

@Service
@EnableConfigurationProperties(ServiceProperties.class)
public class MessageService {

    private final ServiceProperties serviceProperties;

    public MessageService(ServiceProperties serviceProperties) {
        this.serviceProperties = serviceProperties;
    }

    public String message() {
        return this.serviceProperties.getMessage();
    }
}

 

메시지가 잘 조회되는지 Test Code를 작성하여 확인해보겠습니다.

package com.moonsiri.multimodule.service;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest("service.message=Hello, world")
class MessageServiceTest {

    @Resource
    MessageService messageService;

    @Test
    void getMessage() {
        String message = messageService.message();
        Assertions.assertNotNull(message);
        System.out.println(message);
    }

    @SpringBootApplication
    static class TestConfiguration {
    }

}

 

maven deploy로 라이브러리를 레파지토리에 deploy합니다.

 

api 모듈

api 모듈은 service 모듈을 사용하기 위해 dependency 추가를 하고 빌드를 위한 설정을 추가합니다.

<?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">
    <modelVersion>4.0.0</modelVersion>
    <packaging>jar</packaging> <!-- jar로 packaging -->
    
    <!-- 상위 pom.xml 사용 -->
    <parent>
        <groupId>com.moonsiri</groupId>
        <artifactId>multimodule</artifactId>
        <version>0.0.1</version>
    </parent>
    
    <groupId>com.moonsiri.multimodule</groupId>
    <artifactId>api</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.moonsiri.multimodule</groupId>
            <artifactId>service</artifactId>
            <version>0.0.1</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>module-api</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

 

message를 조회하는 api를 구현하겠습니다.

package com.moonsiri.multimodule.controller;

import com.moonsiri.multimodule.service.MessageService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ApiController {

    private final MessageService messageService;

    public ApiController(MessageService messageService) {
        this.messageService = messageService;
    }

    @GetMapping("/message")
    public String message() {
        return messageService.message();
    }

}

 

ApiApplication을 실행합니다.

package com.moonsiri.multimodule;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ApiApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiApplication.class, args);
    }
}

 

 

 

성공!

 

 

+)

멀티 모듈 환경에서 jsp 경로를 찾지 못한다면 IntelliJ Working directory에 $MODULE_WORKING_DIR$ 를 셋팅하면 됩니다.

https://stackoverflow.com/questions/44794588/intellij-run-configuration-spring-boot-vs-maven-issues

 

+)

젠킨스 설정

SSH: Current build result is [NOT_BUILT], not going to run. 에러 발생시 추가

 

 

[Reference]

spring.io/guides/gs/multi-module/

jojoldu.tistory.com/123

www.baeldung.com/spring-boot-multiple-modules

https://github.com/moonsiri/multi-module

728x90
반응형

댓글