2026. 3. 23. 14:22ㆍgradle
📘 build.gradle: 빌드 자동화의 심장
이 파일은 단순한 설정값이 아니라, Groovy DSL(Domain Specific Language)로 작성된 실행 가능한 코드입니다. 각 섹션의 내부 동작 원리를 상세히 설명해 드릴게요.
1. plugins 블록: 빌드 생명주기(Lifecycle)의 확장 🛠️
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.1'
id 'io.spring.dependency-management' version '1.1.0'
}
Gradle은 그 자체로는 아무것도 할 줄 모르는 빈 껍데기입니다. 플러그인을 통해 "능력"을 부여받습니다.
id 'java': Gradle에게compileJava,test,jar와 같은 표준 태스크(Task)를 주입합니다. 이 플러그인이 있어야만 우리가 짠.java파일이.class로 변합니다.id 'org.springframework.boot': 스프링 부트 전용 플러그인입니다. 애플리케이션을 실행하는bootRun태스크와, 모든 의존성을 하나로 합치는bootJar기능을 제공합니다.id 'io.spring.dependency-management': Maven의dependencyManagement기능을 Gradle에서도 쓸 수 있게 합니다. 수백 개의 스프링 관련 라이브러리 버전을 Spring Boot 버전(여기선 3.0.1)에 맞춰 최적으로 고정해 줍니다. 🛡️
2. 프로젝트 메타데이터 & 호환성
group = 'com.example'
version = '1.0.1-SNAPSHOT'
sourceCompatibility = '17'
group&version: 프로젝트를 빌드하여 배포했을 때, 저장소(Repository)에서 이 프로젝트를 식별하는 ID가 됩니다. (예:com.example:project-name:1.0.1-SNAPSHOT)sourceCompatibility = '17': 컴파일러가 소스 코드를 해석할 때 사용할 자바 버전을 지정합니다. Java 17의 신기능(Text Blocks, Switch Expressions 등)을 사용하려면 이 설정이 필수입니다. ☕
3. 🏪 repositories { mavenCentral() } : 전 세계 개발자의 공용 창고
1. Repository(저장소)란 무엇인가?
우리가 dependencies 블록에 implementation 'org.springframework.boot:...'라고 적는 것은 "이런 이름의 라이브러리가 필요해!"라고 리스트를 작성하는 것입니다.
하지만 Gradle은 이 라이브러리가 내 컴퓨터 어디에 있는지, 인터넷 어디에 있는지 처음에는 알지 못합니다. 이때 "자, 이 주소로 가서 찾아봐!"라고 알려주는 곳이 바로 repositories입니다.
2. 왜 하필 mavenCentral() 인가? 🌐
mavenCentral()은 전 세계에서 가장 거대하고 표준적인 자바 오픈소스 라이브러리 저장소입니다.
- 신뢰성: 아파치(Apache), 스프링(Spring), 구글(Google) 등 수많은 기업과 재단이 검증된 라이브러리를 이곳에 올립니다.
- 표준: 과거에는
jcenter()라는 곳도 많이 썼지만, 보안과 유지보수 문제로 현재는mavenCentral()이 사실상 유일한 표준이 되었습니다. - 캐싱 매커니즘: Gradle은 여기서 한 번 다운로드한 파일은 내 컴퓨터의 로컬 저장소(
.gradle/caches)에 보관합니다. 그래서 다음 빌드 때는 인터넷 연결 없이도 아주 빠르게 가져올 수 있죠.
3. 내부 동작 원리 (How it works) ⚙️
Gradle이 빌드를 시작하면 다음과 같은 순서로 움직입니다.
- Dependency 체크:
dependencies목록을 확인합니다. - Local Cache 확인: 내 컴퓨터에 이미 다운로드된 파일이 있는지 먼저 뒤져봅니다.
- Repository 조회: 로컬에 없다면
repositories에 설정된 주소(여기서는 Maven Central 서버)로 요청을 보냅니다. - Verification: 다운로드한 파일이 깨지지 않았는지, 해시값(Checksum)을 비교하여 검증합니다.
4. 만약 mavenCentral() 외에 다른 곳을 써야 한다면? 🏗️
실무에서는 보안상의 이유로 사내 전용 저장소(Nexus, Artifactory)를 쓰거나, 특정 오픈소스의 베타 버전을 받기 위해 다른 주소를 추가하기도 합니다.
repositories {
mavenCentral() // 1순위: 표준 마트
google() // 2순위: 구글 전용 마트 (안드로이드 라이브러리 등)
maven { url "https://repo.spring.io/snapshot" } // 3순위: 스프링 최신 스냅샷 저장소
}
Gradle은 위에서부터 순서대로 라이브러리를 찾아 헤맵니다. 첫 번째에서 찾으면 다음 저장소는 가지 않는 효율적인 방식을 택하죠.
4. jar vs bootJar: 빌드 결과물의 구조적 차이 📦
jar {
enabled = false
}
bootJar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
이 부분이 빌드 프로세스에서 가장 중요합니다.
jar { enabled = false }:- 기본 Java 플러그인의
jar태스크는 오직 사용자가 작성한 클래스 파일만 압축합니다. 외부 라이브러리가 없으므로 실행 시NoClassDefFoundError가 발생합니다. - Spring Boot 환경에서는 필요 없으므로 성능 최적화를 위해 생성 기능을 꺼버리는 것입니다.
- 기본 Java 플러그인의
bootJar { ... }:- 스프링 부트가 제공하는 특수 태스크입니다. 애플리케이션 코드 + 프로젝트에서 사용하는 모든 외부 라이브러리(.jar) + 내장 톰캣 서버를
BOOT-INF/lib폴더 안에 몽땅 집어넣습니다. - 이렇게 만들어진 파일을 Fat JAR라고 부르며, 어디서든 독립적으로 실행 가능해집니다. ✨
- 스프링 부트가 제공하는 특수 태스크입니다. 애플리케이션 코드 + 프로젝트에서 사용하는 모든 외부 라이브러리(.jar) + 내장 톰캣 서버를
duplicatesStrategy: 빌드 과정에서 설정 파일(yml, xml 등)이 여러 라이브러리에서 중복으로 발견될 때, 어떤 것을 우선할지 결정하여 빌드 오류를 막습니다.
5. configurations & sourceSets: 의존성 격리와 경로 설정 🗺️
configurations {
compileOnly {
extendsFrom annotationProcessor
}
asciidoctorExt
}
sourceSets {
main {
java {
srcDirs += "build/generated/sources/annotationProcessor/java/main"
}
}
}
configurations: 특정 라이브러리를 어느 단계에서 사용할지 정의하는 '설정 그룹'입니다.compileOnly { extendsFrom annotationProcessor }: 롬복(Lombok)처럼 컴파일 시점에만 코드를 생성하고 사라지는 도구들을 실제 실행 파일(Runtime)에서 제외하여 용량을 줄입니다. 🧹
sourceSets: Gradle이 컴파일할 대상 파일을 찾는 경로입니다.- QueryDSL은 컴파일 중에 새로운 Java 파일을 생성합니다. 이를 일반 소스 폴더와 섞이지 않게
build/generated/...에 따로 두는데, Gradle에게 "여기도 내 소스 코드 폴더니까 잊지 말고 같이 컴파일해줘!" 라고 길을 알려주는 설정입니다.
- QueryDSL은 컴파일 중에 새로운 Java 파일을 생성합니다. 이를 일반 소스 폴더와 섞이지 않게
6. dependencies: 의존성 관리 전략 🛒
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation 'org.springframework.boot:spring-boot-starter-mail'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
// QueryDSL
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
// JWT
implementation 'io.jsonwebtoken:jjwt:0.9.1'
implementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
}
라이브러리 선언 시 사용하는 키워드마다 클래스패스(Classpath)에 포함되는 범위가 다릅니다.
implementation: 가장 권장되는 방식입니다. 내부 의존성을 숨겨서 빌드 속도를 높이고 결합도를 낮춥니다.compileOnly: 컴파일할 때는 필요하지만, 실행할 때는 이미 환경(예: 톰캣 내부)에 있거나 필요 없는 경우에 사용합니다. (예: Lombok, Servlet API)testImplementation: 테스트 코드(src/test/java) 가 실행될 때만 필요한 라이브러리를 정의합니다runtimeOnly: 코드를 짤 때는 안 쓰지만, 프로그램을 실행할 때만 필요한 라이브러리입니다. (예: DB 드라이버)annotationProcessor: 소스 코드를 스캔해서 새로운 코드나 파일을 생성하는 '코드 생성기'를 지정합니다. (Lombok, QueryDSL) 🤖
7. tasks.named('test'): 품질 검증 🏁
tasks.named('test') {
useJUnitPlatform()
}
useJUnitPlatform(): Gradle은 디폴트로 옛날 버전의 JUnit을 지원할 수도 있습니다. 이 설정은 "JUnit 5(Jupiter) 엔진을 사용해서 테스트를 실행하라" 는 명시적 명령입니다. 이게 없으면 테스트 케이스를 다 작성해 놓고도 "테스트를 찾을 수 없음" 메시지를 볼 수 있습니다.
'gradle' 카테고리의 다른 글
| Creating a Multi Module Project[3] (0) | 2026.03.25 |
|---|---|
| Root 디렉토리의 build.gradle (0) | 2026.03.24 |
| Creating a Multi Module Project[2] (0) | 2026.03.24 |
| Creating a Multi Module Project[1] (0) | 2026.03.24 |
| sync build.gradle (0) | 2026.03.23 |