Spring Boot Multi-Module Project(Gradle)
지난번 spring boot multi-module project 생성하기(maven)에 이어 이번에는 'gradle'을 사용한 멀티 모듈 프로젝트 생성 방법에 대해서 살펴보겠습니다.
multi module project를 적용하는 가장 큰 이유는 하나로 운영하던 서비스가 클라이언트 서비스와 운영 시스템 등, 여러 개로 나뉘는 경우가 발생했을 때 각각의 프로그램에 있는 domain의 동일성을 보장하기 위한 것인데요.
멀티 모듈 프로젝트는 무엇인지, 멀티 모듈 프로젝트를 적용하는 이유와 장점에 대한 내용은 아래 포스팅을 참고해 주시면 좋을 것 같습니다.
(maven 빌드툴로 구성된 프로젝트에서 multi module project를 생성하는 법에 대한 내용도 아래 포스팅에 있습니다.)
2022.09.29 - [Programming/Spring Boot] - Spring Boot Multi Module Project 생성하기(maven)
(gradle) 멀티 모듈 프로젝트 생성 방법
(예시에 사용된 gradle 버전은 gradle-7.6.1이 사용되었습니다.)
1. root 프로젝트 생성
먼저 프로젝트를 생성합니다. 해당 프로젝트는 아래 프로젝트 구조 예시에서 root project가 됩니다.
multi-module: 루트 프로젝트
└─ core-module: Entity, Repository 및 Utility 등
└─ client-module: 사용자 어플리케이션
└─ admin-module: 관리자 애플리케이션
다음은 생성할 멀티 모듈 프로젝트 구조 예시입니다.
루트 프로젝트 아래에는 client, admin, core 모듈이 존재하는데요. core 모듈은 공통적으로 사용될 도메인 등을 정의하고 client, admin 모듈에서 core 모듈을 사용하는 방식으로 구현할 예정입니다.
2. 각각의 모듈(module) 생성
다음과 같은 방식을 통해 프로젝트를 구성할 각각의 모듈을 생성합니다.
(예시에서는 client-module, admin-module, core-module을 생성하였습니다.)
모듈을 생성하고 나서 root project의 settings.gradle 파일을 확인해 보면 위에 보이는 것과 같이 각각의 모듈이 include 되어 있는 것을 확인할 수 있습니다.
(루트 프로젝트는 각 모듈들을 한 번에 담는 역할만 하기 때문에 src 폴더가 필요하지 않습니다. 때문에 현재 상태는 src 폴더를 삭제한 상태입니다.)
3. build.gradle (루트 프로젝트)
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.10'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}
group = 'com.gradle'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
subprojects {
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
}
}
root project의 build.gradle 파일입니다.
여기서 눈여겨봐야 하는 부분은 바로 파일 하단에 있는 'subprojects' 부분인데요.
프로젝트 수준의 build.gradle에서 모듈 수준의 build.gradle을 제어해야 하는 경우 allprojects, subprojects, project 세 가지 옵션을 사용할 수 있으며, 그중에서 subprojects의 경우 해당 프로젝트에 포함된 모든 모듈의 build.gradle을 제어하기 위한 것입니다.
즉, subprojects 부분을 통해 하위의 모든 모듈들(client-module, admin-module, core-module)에 정의된 플러그인 및 의존성을 적용시키는 것입니다.
4. build.gradle (core-module)
plugins {
id 'java-library'
}
group 'com.gradle'
version '0.0.1-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
api 'org.springframework.boot:spring-boot-starter-data-jpa'
// https://mvnrepository.com/artifact/com.mysql/mysql-connector-j
api group: 'com.mysql', name: 'mysql-connector-j'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
// Querydsl
api 'com.querydsl:querydsl-jpa'
api 'com.querydsl:querydsl-core'
// Querydsl JPAAnnotationProcessor 사용 지정
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
annotationProcessor("jakarta.persistence:jakarta.persistence-api") // java.lang.NoClassDefFoundError(javax.annotation.Entity) 발생 대응
annotationProcessor("jakarta.annotation:jakarta.annotation-api") // java.lang.NoClassDefFoundError (javax.annotation.Generated) 발생 대응
}
clean {
delete file('src/main/generated') // IntelliJ Annotation processor 생성물 생성 위치
}
test {
useJUnitPlatform()
}
bootJar {
enabled = false
}
jar {
enabled = true
}
다음으로 core-module의 build.gradle 파일입니다.
해당 파일에는 모든 모듈에서 무조건 사용된다고 판단되는 mysql, jpa, querydsl에 대한 의존성을 추가하였는데요.
(의존성의 경우 당연히 구현하시는 프로젝트마다 다르며, 위 의존성의 경우 단순 예시입니다.)
여기서는 몇 가지 부분에 대해 살펴볼 필요가 있는데요. 첫 번째는 'java-library' 플러그인을 사용한다는 점입니다.
java-library 플러그인은 java 플러그인의 기능을 확장한 것으로 자바 라이브러리에 대하여 api 형식으로 사용자에게 노출을 할 수 있도록 해줍니다.
두 번째로는 dependencies에 정의된 의존성들이 'implementation'이 아니라 'api'로 추가되어 있다는 것인데요.
위에서 이야기한 것처럼 java-library 플러그인은 api와 implementation 두 가지 의존성 정의 방식을 제공하며, api는 라이브러리를 프로젝트 외부에 노출할 때 사용되며, implementation은 프로젝트 내부 컴포넌트에서 사용될 때 사용된다는 차이점이 있습니다.
세 번째는 'bootJar' 부분입니다.
bootJar는 실행 가능한 jar 파일을 빌드하는 역할을 하는데요. 기존에 사용되던 bootRepackage가 Spring Boot 2.0에서 bootJar로 확장되었습니다.
common-module의 경우 실행 가능한 jar 파일로 빌드될 필요가 없기 때문에 enbaeld = false로 되었습니다.
5. build.gradle (client-module)
plugins {
id 'java'
}
group 'com.gradle'
version '0.0.1-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
//core-module
implementation project(':core-module')
}
test {
useJUnitPlatform()
}
bootJar {
enabled = true
}
jar {
enabled = true
}
이어서 client-module의 build.gradle 파일입니다.
해당 파일에서는 dependencies 부분에서 implementation을 통해 core-module에 대한 내용을 사용할 수 있도록 추가하였으며, 나중에 실제로 실행 가능한 jar 파일이 빌드되어야 하기 때문에 bootJar, enabled = true로 설정하였습니다.
(해당 내용은 admin-module의 buile.gradle 파일에도 동일하게 적용되는 내용입니다.)
6. 멀티 모듈 프로젝트 적용 확인
여기까지 client-module의 dependencies -> compileClasspath를 살펴보면 root project에서 추가한 spring-boot-starter, lombok 의존성과 core-module에서 추가한 mysql, querydsl, jpa의 의존성의 classpath를 확인할 수 있습니다.
여기까지 스프링 부트 멀티 모듈 프로젝트(gradle) 생성 방법입니다. 잘못된 내용이나 궁금한 점은 댓글 달아주시면 확인하도록 하겠습니다. 감사합니다.
< 예시 프로젝트 github 주소 >
https://github.com/JianChoi-Kor/multi-module-project-gradle-
< 참고 자료 >
'Programming > Spring Boot' 카테고리의 다른 글
N+1 문제를 해결하기 위한 FetchJoin, 일반 Join과의 차이점은 (0) | 2023.04.22 |
---|---|
Spring Security + OAuth2 + JWT 소셜 인증 구현(google, kakao, naver) (13) | 2023.04.05 |
Spring Boot OAuth2-Client 내부적인 동작 과정 (1) | 2023.03.25 |
Spring Event, @TransactionalEventListener 사용하기 (6) | 2023.03.16 |
(Spring Security + JWT) Refresh Token을 통한 토큰 재발급에 대해서 (0) | 2023.03.12 |