build.gradle

2026. 3. 23. 14:22gradle

📘 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이 빌드를 시작하면 다음과 같은 순서로 움직입니다.

  1. Dependency 체크: dependencies 목록을 확인합니다.
  2. Local Cache 확인: 내 컴퓨터에 이미 다운로드된 파일이 있는지 먼저 뒤져봅니다.
  3. Repository 조회: 로컬에 없다면 repositories에 설정된 주소(여기서는 Maven Central 서버)로 요청을 보냅니다.
  4. 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 환경에서는 필요 없으므로 성능 최적화를 위해 생성 기능을 꺼버리는 것입니다.
  • bootJar { ... } :
    • 스프링 부트가 제공하는 특수 태스크입니다. 애플리케이션 코드 + 프로젝트에서 사용하는 모든 외부 라이브러리(.jar) + 내장 톰캣 서버BOOT-INF/lib 폴더 안에 몽땅 집어넣습니다.
    • 이렇게 만들어진 파일을 Fat 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에게 "여기도 내 소스 코드 폴더니까 잊지 말고 같이 컴파일해줘!" 라고 길을 알려주는 설정입니다.

 

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