Contents
see List개요
Gradle과 Maven은 Java 생태계의 양대 빌드 도구입니다. Maven은 20년 가까이 표준으로 자리 잡았고, Gradle은 유연성과 성능으로 빠르게 점유율을 확대하고 있습니다. 2025년 현재, 어떤 도구를 선택해야 할까요?
이 글에서는 두 도구의 철학, 성능, 생태계, 실전 사용 사례를 비교합니다.
철학과 설계
Maven: 관례 중심 (Convention over Configuration)
Maven은 표준화된 프로젝트 구조와 생명주기를 강제합니다. pom.xml은 선언적이며, 플러그인 기반 아키텍처를 사용합니다.
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>myapp</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
장점: 배우기 쉽고, IDE 지원 완벽, 대부분의 프로젝트에서 동작
단점: 커스터마이징이 어렵고, XML이 장황함
Gradle: 유연성과 프로그래밍 가능성
Gradle은 Groovy/Kotlin DSL로 빌드 로직을 프로그래밍할 수 있습니다. 증분 빌드와 캐싱으로 성능이 뛰어납니다.
// build.gradle.kts (Kotlin DSL)
plugins {
id("java")
id("org.springframework.boot") version "3.2.0"
}
group = "com.example"
version = "1.0.0"
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.withType {
options.release.set(21)
}
// 커스텀 태스크 추가
tasks.register("generateDocs") {
doLast {
println("Generating documentation...")
// 복잡한 로직도 가능
}
}
장점: 유연하고, 빠르며, 멀티 프로젝트 빌드에 강력
단점: 학습 곡선이 가파르고, DSL 숙지 필요
성능 비교
빌드 속도 벤치마크
프로젝트: 100개 모듈, 10,000개 클래스
첫 빌드 (Clean Build)
- Maven: 4분 30초
- Gradle: 3분 45초 (17% 빠름)
증분 빌드 (1개 파일 변경)
- Maven: 45초
- Gradle: 5초 (90% 빠름!)
빌드 캐시 사용 (CI/CD)
- Maven: 지원 안 함
- Gradle: 30초 (캐시 히트 시)
Gradle의 성능 최적화 기능
// gradle.properties
org.gradle.daemon=true # 데몬 모드 (기본)
org.gradle.parallel=true # 병렬 빌드
org.gradle.caching=true # 빌드 캐시
org.gradle.configureondemand=true # 필요한 프로젝트만 설정
// build.gradle.kts
tasks.withType {
options.isIncremental = true # 증분 컴파일
}
// 빌드 캐시 설정
buildCache {
local {
isEnabled = true
}
remote {
url = uri("https://gradle-cache.company.com/cache/")
isPush = true
credentials {
username = "user"
password = "pass"
}
}
}
의존성 관리
Maven BOM (Bill of Materials)
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.2.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 버전 명시 불필요 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
Gradle Platform 및 Version Catalog
// gradle/libs.versions.toml (Gradle 7.0+)
[versions]
spring-boot = "3.2.0"
junit = "5.10.0"
[libraries]
spring-boot-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "spring-boot" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
[plugins]
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
// build.gradle.kts
dependencies {
implementation(libs.spring.boot.web)
testImplementation(libs.junit.jupiter)
}
// 의존성 잠금 (reproducible builds)
dependencyLocking {
lockAllConfigurations()
}
tasks.register("resolveAndLockAll") {
doFirst {
configurations.filter { it.isCanBeResolved }.forEach { it.resolve() }
}
}
멀티 모듈 프로젝트
Maven 멀티 모듈
<!-- 부모 pom.xml -->
<project>
<groupId>com.example</groupId>
<artifactId>parent</artifactId>
<packaging>pom</packaging>
<modules>
<module>core</module>
<module>api</module>
<module>web</module>
</modules>
<dependencyManagement>
<!-- 공통 의존성 버전 관리 -->
</dependencyManagement>
</project>
<!-- 자식 pom.xml -->
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>core</artifactId>
</project>
Gradle 멀티 프로젝트
// settings.gradle.kts
rootProject.name = "myapp"
include("core", "api", "web")
// build.gradle.kts (루트)
subprojects {
apply(plugin = "java")
repositories {
mavenCentral()
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
}
}
// api/build.gradle.kts
dependencies {
implementation(project(":core")) // 모듈 간 의존성
implementation("org.springframework.boot:spring-boot-starter-web:3.2.0")
}
// 복합 빌드 (Composite Build)
// settings.gradle.kts
includeBuild("../shared-library") // 외부 프로젝트 포함
플러그인 생태계
주요 플러그인 비교
기능 Maven Gradle
-------------------------------------------------------------------
코드 커버리지 JaCoCo Plugin JaCoCo Plugin
정적 분석 SpotBugs, Checkstyle SpotBugs, Checkstyle
의존성 분석 Dependency Plugin dependencies task
Docker 빌드 Jib Plugin Jib Plugin
네이티브 이미지 Native Build Tools GraalVM Plugin
테스트 리포트 Surefire Test task (내장)
Gradle 커스텀 플러그인
// buildSrc/src/main/kotlin/MyPlugin.kt
import org.gradle.api.Plugin
import org.gradle.api.Project
class CodeGenPlugin : Plugin {
override fun apply(project: Project) {
project.tasks.register("generateCode") {
doLast {
// 복잡한 코드 생성 로직
val outputDir = project.layout.buildDirectory.dir("generated")
// ...
}
}
}
}
// build.gradle.kts
plugins {
id("code-gen-plugin")
}
tasks.named("compileJava") {
dependsOn("generateCode")
}
선택 가이드
Maven을 선택해야 하는 경우
- 단순한 프로젝트: 표준 구조만으로 충분
- 레거시 통합: 기존 Maven 프로젝트와 통합
- 학습 비용 최소화: 팀원이 Maven에 익숙
- 안정성 우선: 검증된 도구 선호
Gradle을 선택해야 하는 경우
- 대규모 멀티 모듈: 100개 이상의 모듈
- 빌드 성능 중요: CI/CD 시간 단축
- 커스터마이징 필요: 복잡한 빌드 로직
- Android/Kotlin: Gradle이 사실상 표준
- 최신 기술 도입: 혁신적 기능 활용
활용 팁
- Maven Wrapper/Gradle Wrapper 필수: 버전 일관성 보장
- 의존성 분석 정기 실행: mvn dependency:tree 또는 gradle dependencies
- 빌드 캐시 활용: Gradle은 빌드 캐시, Maven은 증분 컴파일 플러그인
- 병렬 빌드: Maven -T 옵션, Gradle --parallel
- CI/CD 최적화: Gradle의 원격 빌드 캐시로 팀 전체 빌드 속도 개선
마무리
Maven과 Gradle은 각각의 강점이 있으며, 프로젝트 특성에 따라 최적의 선택이 달라집니다. 단순한 프로젝트는 Maven으로 충분하지만, 대규모 멀티 모듈이나 빌드 성능이 중요하다면 Gradle이 압도적으로 유리합니다.
2025년 현재, Spring Boot, Micronaut, Quarkus 같은 주요 프레임워크는 모두 Gradle을 공식 지원하며, Android와 Kotlin은 Gradle이 사실상 표준입니다. 새 프로젝트를 시작한다면 Gradle을 강력히 추천합니다.
하지만 Maven의 단순함과 안정성도 여전히 큰 장점입니다. 프로젝트의 복잡도, 팀의 숙련도, 빌드 성능 요구사항을 종합적으로 고려하여 선택하시기 바랍니다.