Spring 멀티 모듈 (Gradle)
Spring 멀티 모듈 (Gradle)
하나의 저장소 안에 여러 Spring 애플리케이션을 함께 두면 공통 코드의 위치·빌드 단위·의존 방향을 정해야 합니다. Gradle 의 멀티 프로젝트 빌드는 이런 구조를 다루기 위한 표준 도구입니다.
1. Gradle 멀티 프로젝트에 대한 이야기
Gradle 자체는 Hans Dockter 가 시작했고 2007 년 첫 공개, 2012 년 1.0 릴리스로 알려져 있습니다. 멀티 프로젝트 빌드는 Gradle 의 핵심 기능 중 하나로, 루트 프로젝트 아래 여러 하위 프로젝트(서브프로젝트)를 두고 각각을 독립 모듈로 빌드합니다.
핵심 파일 셋입니다.
| 파일 | 역할 |
|---|---|
settings.gradle(.kts) |
루트 이름과 include 로 서브프로젝트 등록. |
루트 build.gradle(.kts) |
subprojects {} · allprojects {} 로 공통 설정 부여. |
<module>/build.gradle(.kts) |
모듈별 의존·플러그인. |
Spring Modulith 는 Spring 팀이 2022 년 공개한 라이브러리로, 단일 애플리케이션 안에서 모듈 경계를 패키지 수준에서 관리·검증하는 도구입니다. 멀티 프로젝트와는 결이 다릅니다.
2. settings.gradle 의 include
rootProject.name = 'platform'
include 'common'
include 'foo-api'
include 'bar-api'
include 된 디렉토리는 각각 독립 모듈로 컴파일·테스트·패키징됩니다. 서브프로젝트 간 의존은 dependencies { implementation project(':common') } 처럼 프로젝트 참조로 표현합니다.
3. subprojects 블록
루트 build.gradle 에서 모든 서브프로젝트에 공통 설정을 한 번에 적용할 수 있습니다.
subprojects {
apply plugin: 'java'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
repositories { mavenCentral() }
tasks.withType(Test) { useJUnitPlatform() }
}
allprojects 는 루트까지 포함, subprojects 는 루트 제외입니다. Spring Boot 플러그인은 보통 bootJar 가 필요한 실행 모듈에만 적용하고, 라이브러리 모듈에는 io.spring.dependency-management 만 적용하는 식으로 분리합니다.
4. common + service-api 일반 패턴
여러 서비스가 같은 저장소에서 자라는 경우의 흔한 구성입니다.
platform/
├── settings.gradle
├── build.gradle # subprojects 공통
├── common/ # 도메인 무관 유틸·예외·DTO 베이스
│ └── build.gradle
├── foo-api/ # 서비스 A 실행 모듈 (bootJar)
│ └── build.gradle
└── bar-api/ # 서비스 B 실행 모듈 (bootJar)
└── build.gradle
common 은 라이브러리 jar, *-api 는 실행 가능한 boot jar 로 빌드됩니다. 의존 방향은 단일 — *-api → common. 역방향 (common → *-api) 은 모듈 경계를 깹니다.
5. Maven 멀티모듈과의 비교
| 항목 | Gradle | Maven |
|---|---|---|
| 첫 릴리스 | 2007 | 2004 (1.0) |
| 빌드 스크립트 | Groovy/Kotlin DSL | XML (pom.xml) |
| 멀티모듈 선언 | settings.gradle include |
부모 pom.xml <modules> |
| 빌드 캐시 | 빌드/구성 캐시 내장 | 기본 제공 안 함 |
| 병렬 빌드 | 기본 지원 | -T 옵션 |
Maven 은 선언적·관례 중심이고 Gradle 은 스크립트 기반의 유연성을 제공합니다. 어느 쪽이 절대 우월하다 말하기는 어렵고, 팀이 더 익숙한 쪽이 운영 비용이 낮습니다.
6. Spring Modulith 와 단일 모듈
Spring Modulith 는 단일 애플리케이션 jar 안에서 패키지를 모듈로 취급하고 모듈 간 의존을 검증·문서화합니다. 멀티 프로젝트가 빌드 단위 분리라면 Modulith 는 런타임은 한 덩어리이되 코드 경계를 강제하는 접근입니다. 둘은 양립 가능합니다.
작은 서비스라면 모듈을 나누지 않고 패키지로만 구분하는 편이 운영이 단순할 수 있습니다. 모듈 분리는 빌드 시간·재사용성·소유권 분리 같은 이득과 설정 복잡도의 트레이드오프입니다.
7. 모듈 분리 기준
- 도메인 기준 —
order-api·payment-api·common. 서비스 단위가 명확할 때 자연스럽습니다. - 기술 레이어 기준 —
web·domain·infrastructure. 헥사고날·클린 아키텍처 변형에서 종종 쓰입니다.
도메인과 레이어를 동시에 나누면 모듈이 폭발적으로 늘어납니다. 보통은 도메인 우선으로 자르고 큰 도메인 안에서만 레이어 분리합니다.
8. 버전 카탈로그
Gradle 7.0+ 의 표준 의존 버전 관리 방식입니다.
# libs.versions.toml
[versions]
spring-boot = "3.4.1"
[libraries]
spring-boot-starter-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "spring-boot" }
여러 모듈이 같은 버전을 공유할 때 단일 출처로 다룰 수 있습니다.
9. 자주 걸리는 자리
순환 의존 — a → b → a. Gradle 이 빌드 시 막아 주지만 설계 의도와 다른 우회로 (예: 인터페이스를 common 으로 끌어올림) 로 우회되는 경우가 있습니다.
bootJar 의도치 않은 적용 — 라이브러리 모듈에 Spring Boot 플러그인을 그대로 붙이면 일반 jar 가 생성되지 않을 수 있습니다. bootJar { enabled = false } 와 jar { enabled = true } 조합을 명시합니다.
api vs implementation — api 로 노출된 의존은 하위 프로젝트로 전파됩니다. 노출 범위를 좁히려면 implementation 을 기본으로 합니다.
테스트 fixture 공유 — 모듈 간 테스트 헬퍼 공유는 java-test-fixtures 플러그인으로 표준화된 방법이 있습니다.
하고픈 말
멀티 모듈은 작은 서비스에 들이면 빌드·설정 부담이 코드 양보다 빠르게 자랍니다. 도메인이 두 개 이상 분명히 나뉘는 시점부터 도입하는 편이 안전합니다. 한 번 자리잡으면 빌드 캐시·병렬 빌드·소유권 분리의 이득이 보입니다.
Next
- spring-webflux-vs-mvc
Gradle Multi-Project Builds · Gradle Version Catalogs · Spring Boot Gradle Plugin · Spring Modulith · Maven Multi-Module Project · Java Test Fixtures 를 참고합니다.