Gradle과 Maven은 빌드 자동화 도구로 Task 단위로 빌드과정을 나누고, 각 Task간의 의존관계를 이용하여 빌드에 필요한 일련의 과정들이 순차적으로 실행되도록 자동화한다. 예를든다면 테스트작업이 성공해야만 다음 Task가 실행되도록 빌드루틴을 짤 수 있다.
보통 Spring 프로젝트를 생성할 때 Maven이나 Gradle 중 하나를 선택하도록 소개된다.
Maven은 pom.xml
에서 프로젝트에 필요한 설정들을 작성하며,
Gradle은 build.gradle
이라는 파일에 Groovy 또는 Kotlin을 이용해 스크립트를 작성한다.
Gradle은 크게 유저 홈 디렉토리와 프로젝트 루트 디렉토리, 총 두개의 메인 디렉토리로 구성된다.
유저 홈 디렉토리는 보통 C:\Users\<USERNAME>\.gradle
경로에 위치하며 전역적인 설정 값과 초기화 스크립트, 캐시, 로그파일이 위치한다.
이 경로는 GRADLE_USER_HOME
라는 환경변수에 세팅된다.
├── caches
│ ├── 4.8
│ ├── 4.9
│ ├── ⋮
│ ├── jars-3
│ └── modules-2
├── daemon
│ ├── ⋮
│ ├── 4.8
│ └── 4.9
├── init.d
│ └── my-setup.gradle
├── jdks
│ ├── ⋮
│ └── jdk-14.0.2+12
├── wrapper
│ └── dists
│ ├── ⋮
│ ├── gradle-4.8-bin
│ ├── gradle-4.9-all
│ └── gradle-4.9-bin
└── gradle.properties
위 형태의 디렉토리 구조를 가지고 있으며, Gradle 버전에 따른 캐시 디렉토리와 공유 캐시, 로그 등의 정보가 저장되어있다.
프로젝트 루트 디렉토리는 프로젝트 생성과 함께 만들어진다. Gradle Wrapper 설정 디렉토리인 gradle
과 빌드 관련 디렉토리인 .gradle
, build
등이 포함된다.
├── .gradle
│ ├── 4.8
│ ├── 4.9
│ └── ⋮
├── build
├── gradle
│ └── wrapper
├── gradle.properties
├── gradlew
├── gradlew.bat
├── settings.gradle.kts
├── subproject-one
| └── build.gradle.kts
├── subproject-two
| └── build.gradle.kts
└── ⋮
디렉토리 구조는 위 형태와 같다.
gradle
에는 Gradle Wrapper와 관련된 설정파일들이 존재한다.
이는 빌드 스크립트를 실행시키는 gradlew
와 관련된 설정을 의미한다.
.gradle
에는 Gradle 버전에 따라 빌드에 필요한 캐시 정보가 저장된다.
예를들어, 의존성 정보나 Task 실행 기록 등이 캐시형태로 관리된다.
build
는 실질적인 빌드 결과물이 저장되는 디렉토리다.
컴파일된 클래스파일과 JAR 파일, 테스트 결과 등이 저장된다.
Gradle Wrapper인
gradlew
와graldew.bat
은 Gradle을 설치하지 않고도 Gradle 프로젝트를 빌드할 수 있게 해준다.또한, Wrapper 설정에 따른 일관적인 버전의 Gradle을 사용할 수 있게 해준다.
Spring 프로젝트 생성 시, gradle.properties
는 자동으로 생성되지 않는다. 이는 프로젝트에 대한 Gradle 설정파일이므로 필요에 따라 직접 생성해줘야 한다.
Gradle의 빌드는 각 Task간의 의존관계에 따라 순차적으로 실행된다.
빌드 스크립트를 작성함으로써 이러한 Task 간의 의존관계를 설정할 수 있다.
Gradle은 Task들을 실행하기 전에 위 이미지처럼 방향성을 지닌 비순환형태의 작업 그래프를 생성한다.
빌드과정은 크게 3가지의 단계로 구분된다.
1. Initialization 단계
settings.build
파일 식별Settings
인스턴스를 생성하고, 빌드를 구성하는 프로젝트 결정- 모든 프로젝트에 대한
Project
인스턴스 생성
2. Configuration 단계
- 빌드에 참여하는 모든 프로젝트의 빌드 스크립트(
build.gradle
) 확인- Task 그래프 생성
3. Execution 단계
- 그래프에 따라 Task들의 실행 순서 결정
- 병렬적으로 Task 실행
이 파일에는 빌드과정의 초기화 단계에서 생성되는 Settings
인스턴스에 대한 내용들이 작성된다.
주 목적은 빌드에 참여할 프로젝트 정보들을 관리하는 것이다.
작성 언어에 따라 settings.gradle(Groovy)
나 settings.gradle.kts(Kotlin)
으로 구분된다.
이 파일에 의해 생성되는 Settings
인스턴스에 대한 문서는 이 곳(Groovy)과 이 곳(Kotlin)에서 확인할 수 있다.
표준 속성들만 살펴보자면, 주로 사용되는 속성 값들은 아래와 같다.
이름 | 설명 |
---|---|
buildCache | 빌드 성능 향상을 위한 빌드 캐시 설정이 작성된다 |
plugins | settings 에서 사용하는 플러그인들이 작성된다 |
rootDir | 빌드의 루트 디렉토리(= 루트 프로젝트의 디렉토리)가 작성된다 |
rootProject | 빌드의 루트 프로젝트가 작성된다 |
settings | 현재 settings 객체 자체를 의미한다 |
주로 사용되는 메서드들은 아래와 같다.
이름 | 설명 |
---|---|
include() | 괄호 안의 프로젝트를 빌드에 포함시킬 때 사용된다 |
includeBuild() | 복합 빌드에 다른 빌드를 포함시킬 때 사용된다 |
includeBuild()
독립적으로 빌드가 가능한 프로젝트 A, B가 있다고 가정할 때, A프로젝트가 B프로젝트를 의존하는 상황에서 A프로젝트의 빌드과정에 B프로젝트 빌드과정을 포함시키는 식으로 사용된다.
// 빌드에 대한 플러그인 버전과 저장소 관리
// 프로젝트에서 사용할 플러그인과 저장소에 대한 내용 작성
pluginManagement {
repositories {
gradlePluginPortal()
}
}
// Settings 객체에만 영향을 끼칠 플러그인 관리
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}
// 루트 프로젝트 이름
rootProject.name = 'simple-project'
// 프로젝트 전반에 걸친 종속성 관리를 위한 저장소 설정
dependencyResolutionManagement {
repositories {
mavenCentral()
}
}
// 빌드에 포함될 프로젝트 목록 설정
include("sub-project-a")
include("sub-project-b")
include("sub-project-c")
settings.gradle
파일의 작성 예시는 위 형태와 같다.
본질적으로 스크립트 항목들은 Gradle API의 설정 객체에서 메서드를 호출한다.
즉,
include()
는 사실settings.include()
형태로 호출된다.
이 파일에는 빌드과정의 초기화 단계에서 생성되는 Project
인스턴스에 대한 내용들이 작성된다.
settings.gradle
처럼 작성 언어에 따라 *.gradle(Groovy)
나 *.gradle.kts(Kotlin)
으로 구분된다.
이 파일에 의해 생성되는 Project
인스턴스에 대한 문서는 이 곳(Groovy)과 이 곳(Kotlin)에서 확인할 수 있다.
표준 속성들만 살펴보자면, 주로 사용되는 속성 값들은 아래와 같다.
이름 | 타입 | 설명 |
---|---|---|
name | String | 프로젝트 디렉토리의 명칭이 작성된다 |
path | String | 현재 프로젝트 경로가 작성된다 |
description | String | 현재 프로젝트에 대한 설명이 작성된다 |
dependencies | DependencyHandler | 현재 프로젝트의 종속성 핸들러를 반환한다 |
repositories | RepositoryHandler | 현재 프로젝트의 저장소 핸들러를 반환한다 |
layout | ProjectLayout | 프로젝트의 여러 중요위치에 대한 엑세스를 제공한다 |
group | Object | 현재 프로젝트의 그룹이 작성된다( ex: group = 'com.example' |
version | Object | 현재 프로젝트의 버전이 작성된다( ex: `version = '0.0.1-SNAPSHOT') |
주로 사용되는 메서드들은 아래와 같다.
이름 | 설명 |
---|---|
uri() | 현재 프로젝트 디렉토리 기준으로 URI 경로에 대한 상태경로를 지정한다 |
task() | 주어진 이름의 Task를 생성하고 프로젝트에 추가한다 |
// Gradle 확장, 또는 프로젝트 구성의 모듈화와 재사용을 위한 플러그인 설정
// 이 예시에서는 현재 프로젝트가 java 애플리케이션임을 의미
plugins {
id 'application'
}
// 종속성 다운로드를 위한 저장소 설정
// 이 예시에서는 Maven Central Repository 사용
repositories {
mavenCentral()
}
// 프로젝트에 사용될 종속성 목록 설정
// 앞선 repositories에 설정된 저장소에서 이미 컴파일된 클래스 라이브러리를 가져옴
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.3'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'com.google.guava:guava:32.1.1-jre'
}
// 앞선 plugins 를 통해 추가된 application 플러그인을 이용해 프로젝트 정보를 설정
application {
mainClass = 'com.example.Main'
}
// JUnit5를 이용해 테스트를 실행하도록 지정
tasks.named('test', Test) {
useJUnitPlatform()
}
// exclude를 통해 제외한 파일을 제외하도록 javadoc Task 수정
tasks.named('javadoc', Javadoc).configure {
exclude 'app/Internal*.java'
exclude 'app/internal/*'
}
// 신규 Task 등록
// from 경로의 모든 파일들을 Reports.zip 으로 압축하고, /dir 경로에 저장
// tasks.create<Zip>("zip-reports") { } 형식으로 작성할 수도 있지만 권장되지 않음
tasks.register('zip-reports', Zip) {
from 'Reports/'
include '*'
archiveFileName = 'Reports.zip'
destinationDirectory = file('/dir')
}
build.gradle
파일의 작성 예시는 위 형태와 같다. 좀 더 자세한 내용은 Docs 문서를 참고하자.