일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Spring
- AI
- MySQL
- kotlin coroutine
- 공부
- APM
- Pinpoint
- CKA
- minikube
- 정보처리기사실기 기출문제
- 코틀린 코루틴의 정석
- 정보처리기사 실기 기출문제
- 오블완
- PETERICA
- 정보처리기사 실기
- aws
- AWS EKS
- IntelliJ
- kotlin querydsl
- Elasticsearch
- mysql 튜닝
- kotlin spring
- Linux
- kotlin
- 기록으로 실력을 쌓자
- Kubernetes
- CloudWatch
- CKA 기출문제
- 티스토리챌린지
- Java
- Today
- Total
피터의 개발이야기
[Kotlin] Spring Boot 멀티모듈 프로젝트 구성 본문
ㅁ 들어가며
ㅇ api, batch, gateway, internel...를 구성하면서, 반복되는 Util, Dto, Entity, Service, Enum...을 만나게 된다.
ㅇ 동일한 파일을 여러번 변경하기도 하고, 프로젝트별로 변경된 Util은 공통으로 관리하기도 어렵다.
ㅇ 예로, 프로젝트가 10개이면, dto 하나 수정하고 PR 10번 올려야 한다.
ㅇ 공통 기능을 모듈화하여 코드의 재사용성을 높이고 의존성 관리를 개선하기 위해 멀티 모듈은 꼭!! 필요하다.
ㅇ 이번 글에서는 Kotlin Spring Boot 프로젝트를 멀티모듈로 구성하는 방법을 정리하였다.
ㅁ 멀티 모듈 프로젝트의 필요성
ㅇ 코드 재사용성
- 공통 기능을 개별 모듈에서 분리하여 공통으로 만들면 재사용이 가능하다.
- 중복코드를 줄이고, 유지보수를 용이하게 한다.
ㅇ 관심사 분리
- 각 모듈의 기능이나 도메인에 집중하여 코드의 구조를 단순화하고 관리가 쉬워진다.
ㅇ 의존성 관리 개선
- 각 모듈의 의존성을 명확히 정의하고 관리할 수 있다.
- 불필요한 의존성을 줄이고 모듈 간 결합도를 낮출 수 있다.
ㅇ 배포의 용이성
- 모듈은 독립적으로 배포될 수 있는 코드의 단위를 말하며, 이러한 코드 뭉치를 멀티 모듈이라고 한다.
- 특정 기능만 업데이틀를 하거나 롤백할 수 있다.
ㅁ 프로젝트 구조
ㅇ 멀티 모듈 프로젝트는 일반적으로 다음과 같은 구조를 가진다
kotlin-multi-module
│
├── build.gradle.kts
├── settings.gradle.kts
│
├── core
│ ├── build.gradle.kts
│ └── src/main/kotlin/com/peterica/core
│
├── rest
│ ├── build.gradle.kts
│ └── src/main/kotlin/com/peterica/rest
│
└── domain
├── build.gradle.kts
└── src/main/kotlin/com/peterica/domain
ㅇ domain은 dto, enum, error code와 같은 기초 정보를 담고 있다.
ㅇ core는 정보를 핸들링하는 서비스 영역을 그룹화 하여 batch나 api에서 service를 재사용할 수 있도록 한다.
ㅇ rest는 외부에 서비스를 제공하는 역할을 한다.
ㅇ rest는 core를, core는 domain에 의존하는 형태로 사용된다.
ㅇ 반대로 rest, core, domain 순으로 재사용성이 높다.
ㅇ 우선 루트 프로젝트를 생성하고 모듈의 골격을 만들어 보자.
ㅁ 루트 프로젝트 생성
ㅇ IntelliJ IDEA를 사용하여 새로운 Gradle 프로젝트를 생성한다.
ㅇ 프로젝트 이름은 kotlin-multi-module로 설정한다.
ㅇ (옵션) MySQL과 JPA 종속성을 추가하였다.
ㅁ 서브모듈 폴더 생성
ㅇ 루트 프로젝트 내에 새로운 디렉토리를 만들어 각 모듈을 생성한다 (예: rest, core, domain)
ㅇ 각 모듈 디렉토리에 `build.gradle.kts` 파일을 생성한다.
ㅇ root의 src는 제거한다.
ㅁ 루트 build.gradle.kts 설정
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.js.translate.context.Namer.kotlin as kotlin
plugins {
id("java")
id("org.springframework.boot") version "3.2.5" apply false
id("io.spring.dependency-management") version "1.1.4" apply false
id("org.hibernate.orm") version "6.4.9.Final"
kotlin("jvm") version "1.9.23" apply(false)
kotlin("plugin.jpa") version "1.9.23"
kotlin("plugin.spring") version "1.9.23"
kotlin("kapt") version "1.9.23"
}
configure(allprojects) {
repositories {
mavenCentral()
}
}
group = "com.peterica"
version = "0.0.1-SNAPSHOT"
configure(subprojects) {
apply {
plugin("org.springframework.boot")
plugin("kotlin")
println("java")
plugin("io.spring.dependency-management")
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.jetbrains.kotlin:kotlin-reflect")
runtimeOnly("com.mysql:mysql-connector-j")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
tasks.withType<Test> {
useJUnitPlatform()
}
}
ㅇ 공통 플러그인과 의존성을 설정한다.
ㅇ subprojects 블록을 사용하여 모든 서브모듈에 공통 설정을 적용한다.
ㅇ 모듈 개별 설정은 모듈의 build.gradle.kts 설정하면 된다.
ㅁ 모듈 build.gradle.kts 설정
dependencies {
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.jetbrains.kotlin:kotlin-reflect")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
ㅇ 샘플로 3개 모듈 동일하게 적용하였다.
ㅇ 루트에서 적용한 공통 설정 외에 개별 모듈에서 필요한 의존성을 추가다.
ㅇ 모듈 작성이 완료되면 서브모듈을 Gradle에 인식시켜야 한다.
ㅁ settings.gradle.kts 설정
rootProject.name = "kotlin-multi-module"
include("rest", "core", "domain")
ㅇ 루트 프로젝트의 settings.gradle.kts에 서브모듈을 포함시킨다.
ㅇ Gradle에 서브모듈을 인식 시키게 된다.
ㅇ Gradle의 Reload 버튼을 클릭하면 신규 모듈이 나타나고, 모듈의 Task가 별도로 설정된다.
ㅁ 모듈 간 의존성 설정
ㅇ 지금까지 물리적 공간적 모듈 설정이었다면, Gradle에 논리적인 모듈 설정을 해야한다.
ㅇ 필요한 경우 모듈 간 의존성을 설정한다.
ㅇ rest모듈은 core모듈과 domain모듈에 의존한다.
ㅁ 애플리케이션 구조화
ㅇ 각 모듈의 패키지 구조를 설계하고 코드를 적절히 배치해야 한다.
ㅇ 모듈의 종류와 그룹이 많아지면, 서로 간에 의존성이 생기게 된다.
ㅇ 현재의 멀티모듈은 간단해서 이런 일이 거의 없겠지만, 규모가 커지면 다음과 같은 에러가 발생한다.
Circular dependency between the following tasks:
:core:classes
\--- :core:compileJava
+--- :core:compileKotlin
| +--- :core:kaptKotlin
| | \--- :core:kaptGenerateStubsKotlin
| | \--- :domain:jar
| | +--- :domain:classes
| | | \--- :domain:compileJava
| | | +--- :core:jar
| | | | +--- :core:classes (*)
| | | | +--- :core:compileJava (*)
| | | | +--- :core:compileKotlin (*)
| | | | \--- :core:kaptKotlin (*)
| | | \--- :domain:compileKotlin
| | | +--- :core:jar (*)
| | | \--- :domain:kaptKotlin
| | | \--- :domain:kaptGenerateStubsKotlin
| | | \--- :core:jar (*)
| | +--- :domain:compileJava (*)
| | +--- :domain:compileKotlin (*)
| | \--- :domain:kaptKotlin (*)
| \--- :domain:jar (*)
\--- :domain:jar (*)
ㅇ core는 domain을 domain은 core를 서로 참조하면서 순환 참조 오류가 발생한다.
ㅇ 이런 경우를 위해 common모듈을 추가해 보자.
common모듈 추가
ㅇ 물리적 폴더 구조를 생성하고, gradle에 모듈을 인식시킨다.
ㅇ 그리고 마지막으로 참조하는 모듈의 의존성을 선언한다.
ㅁ 빌드 및 실행
ㅇ 루트 디렉토리에서 gradle build하면 전체 프로젝트가 빌드되면서 모듈별 jar가 형성된다.
ㅇ 이 방식으로 코드를 모듈화하면 관심사를 분리하고, 재사용성을 높이며, 프로젝트 구조를 더 명확하게 만들 수 있다.
ㅁ 함께 보면 좋은 사이트
ㅇ SpringDoc- Creating a Multi Module Project
ㅇ [Spring Boot] Kotlin Querydsl 적용 (with. Mono repo, Multi module)
ㅇ git - kotlin-spring-multi-module-example
ㅇ [Spring] 스프링부트로 멀티 모듈 프로젝트 진행하기
ㅇ Spring Boot + kotlin 프로젝트에 ktlint 적용하기 (Multi module 통합 관리하기)
ㄴ 설계의 방향성을 잘 설명함.
'Programming > Kotlin' 카테고리의 다른 글
[Kotlin] Spring 멀티모듈, JAR 파일로 배포하는 방법 (0) | 2024.08.22 |
---|---|
[Kotlin] Paging query needs to have a Pageable parameter 문제 해결 (0) | 2024.08.21 |
[Kotlin] Kotlin JDSL 문법 정리 (0) | 2024.08.16 |
[Kotlin] QueryDSL의 Q클래스 생성 과정에서 Entity 참조 오류 해결 (0) | 2024.08.15 |
[Kotlin] Kotlin에서 all-open과 no-arg의 필요성 (0) | 2024.08.14 |