JAVA/Spring Boot

Spring Boot, Gradle 멀티 모듈 프로젝트 실전 예제

주코식딩 2022. 12. 28. 12:03

시작하기 전에..

멀티 모듈 프로젝트란 무엇인가에 대해 아주 자세히 쓰여있다. 

개념적인 부분은 아래 링크를 통해 이해하자.

 

멀티모듈 설계 이야기 with Spring, Gradle | 우아한형제들 기술블로그

{{item.name}} 멀티 모듈 설계 이야기 안녕하세요. 배달의민족 프론트 서버를 개발하고 있는 권용근입니다. 멀티 모듈의 개념을 처음알게 되었을 때부터 현재까지 겪었던 문제점들과 그것을 어떻게

techblog.woowahan.com

 

멀티 모듈을 설정하는 방법은 꽤나 많지만 부가적인 작업을 최대한 하지 않는 방식으로 설정했다.

 

Gradle 에서 권장하는 최신 방식은 자식 모듈에서 부모 모듈을 명시하게끔 했는데 자식 모듈만 봐서는 이게 뭘하는 코드인지 파악하기 힘들다는 이유다.

 

하지만 프로젝트를 생성 할 때 마다 이걸 명시해 주는건 너무 번거로워서 사용하지 않았다.

 

- 최신방식

 

Structuring and Building a Software Component with Gradle

If you are building a software of a certain size with Gradle, you have two basic structuring mechanisms. First, this chapter describes how to structure your software project using a Gradle multi-project. In this documentation, we consider this to be a sing

docs.gradle.org

 

나는 subprojects 와 모듈별로 build.gradle 을 사용하는 방식을 썼다.

 

 

프로젝트 생성

우선 Gradle-Groovy 로 프로젝트를 생성한다.

java version은 아무거나 사용해도 됨

 

간단하게 Spring Web 과 Lombok 정도만 추가한다.

Java 17 미만을 사용하고 있다면 Spring Boot 버전이 3.x.x 가 아닌지 꼭 확인해야한다.

 

src 폴더는 사용하지 않으니 삭제한다. (부모 프로젝트는 모듈만을 담는다.)

 

부모 프로젝트 build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '2.7.7'
    id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

// 모든 프로젝트에 적용.
allprojects{
    group = 'com.example'
    version = '0.0.1-SNAPSHOT'
    sourceCompatibility = '17'

    repositories {
        mavenCentral()
    }
}

// 서브 프로젝트 전체에 적용.
subprojects{
    apply plugin: 'java'
    // 위에서 불러온 plugin 을 적용 시켰으므로 버전을 명시하지
    // 않아도 자식 프로젝트에서 2.7.7 버전을 받게된다.
    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'

    // 공통적으로 사용하는 dependencies
    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
        compileOnly 'org.projectlombok:lombok'
        annotationProcessor 'org.projectlombok:lombok'
    }

    tasks.named('test') {
        useJUnitPlatform()
    }
}

// 서브 프로젝트 개별 설정
// 이곳에서 lombok 같은 dependency 를 추가 할 수 있으나
// 해당 모듈 내에서도 추가 할 수 있기때문에 프로젝트간의 관계만 명시하도록 하자.
project(':webclient') {
    dependencies {
        implementation project(':core')
    }
}
project(':core') {
    dependencies {

    }
}

 

프로젝트 구조 (cmd +  ;) (ctrl + arlt + shift + S)

 

1. 모듈 탭 - 추가(+) 버튼 - 새 모듈 or 프로젝트 최상단 우클릭 - 새로 만들기 - 모듈

 

1-1. 새 모듈로만드는 법은 번거로우니 Spring Initailizr 사용

Project Name 과 Gradle - Groovy만 기억하고 나머지는 대충 넘겨도 된다.

1-2. 쓸모없는 파일 삭제

선택한 파일들은 필요없으니 삭제해야만 한다. (Gradle은 부모 프로젝트에서만 돌리므로 없어도 된다. 괜히 있으면 에러 뜸)

다만 Application.java 파일은 서버를 돌려야하는 프로젝트일 경우 삭제하면 안된다.(batch server, api server)

webclient 폴더 내에 생긴 .gradle 폴더도 삭제해준다.

만들어둔 모듈이 없다면 core 역시 동일하게 생성한다.

 

2. 모듈 탭 - 추가(+) 버튼 - 모듈 가져오기 (재사용 시 사용)

 

2-1. 모듈 가져오기를 사용하려면 서브 프로젝트 폴더를 부모 프로젝트 최상단에 두어야만 한다.

재사용을 위해 module 폴더를 만들어 두었다. module - core  복사> multi-module-project - core

module은 새 모듈의 설정(1-2)에 실제 java파일까지 추가되어 있어야 한다. (java 파일이 없으면 모듈로 인식하지 못한다.)

 

2-2. 메인 프로젝트를 지정한다.

사진 처럼 최상단에 core 폴더가 있는지 꼭 확인하자. (새 모듈로 만든 webclient 폴더 역시 최상단에 있다.)

 

2-3. 기존 소스에서 모듈 생성 - 해당하는 모듈 선택

만약 부모 프로젝트의 main과 test가 뜬다면 src 폴더 삭제를 잊지 말자.

 

2-3-1. 선택한 모듈이 하나여서 그런지 이름도 이상하고 경로도 부모 프로젝트로 잡혔다.

webclient를 모듈에서 제거한 뒤 둘다 추가하거나 core 폴더를 지정해서 모듈을 추가해주자.

 

2-3-2. webclient 모듈 제거 후(폴더는 삭제되지 않음) 다시 등록 

이 방법 사용시 프로젝트 다시 만들어야 함. core폴더를 지정해서 모듈 불러오기를 사용하자.

2개 이상일 경우에는 부모 프로젝트 폴더를 선택해서 간편하게 추가 할 수 있다.

 

2-4. 모듈명과 경로가 제대로 인식되었다

weclient1 이라고 뜬다면 삭제 후 적용 버튼을 눌렀나 확인

 

서브 프로젝트(webclient) build.gradle

(생략된 것이 아니고 아래 설정만 있으면 끝이다.)

// 아래 두 설정은 서버가 아니고 class 파일만 있을 경우 작성
bootJar {
   enabled = false
}
jar {
   enabled = true
}

// 해당 모듈에서만 사용할 의존성 추가
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-webflux'
	implementation 'io.micrometer:micrometer-core'
}

 

 

서브 프로젝트(core) build.gradle

bootJar {
    enabled = false
}
jar {
    enabled = true
}

dependencies {
// 확인용으로 추가 함, 보통 core(공통 모듈)에는 dependency 를 추가하지 않는다.
    implementation 'mysql:mysql-connector-java:8.0.30'
}

 

부모 프로젝트 settings.gradle

include 에 모듈을 추가 해야만 한다.

rootProject.name = 'multi-module-project'

include 'webclient', 'core'

 

빌드 후 의존성 확인

우측 gradle탭에 설정한 대로 dependencies가 추가 되었는지 확인한다.

 

추가 설정..?

많은 글이 해당 설정을 해줘야 빨간줄이 안뜬다고 하던데 나는 이상이 없지만 혹시 몰라서 남겨둔다. 

어노테이션 처리 활성화를 체크 해준다.

 

마치며..

멀티 모듈 프로젝트의 가장 큰 단점은 의존성 설계를 제대로 하지 않을 경우 프로젝트가 오히려 더 무거워지고 유지보수가 더 어려워 진다는 점이다. 

꼭 모든 프로젝트를 멀티 모듈 프로젝트로 할 필요는 없지만 간단한 프로젝트라도 JPA와 Controller를 분리해야 하고 Exception 같은 재사용 가능한 모듈이 있으니 한 번 쯤은 활용해 보자.