gradle 사용법
Spring 프로젝트를 만들고보니 build.gradle 파일에 다음과 같은 간단한 코드가 들어있었다.
plugins {
id 'org.springframework.boot' version '2.4.2-SNAPSHOT'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
group = 'com.test'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
프로젝트에 필요한 설정을 해보자.
플러그인 의존성 관리를 위한 설정
buildscript {
ext {
springBootVersion = '2.4.2-SNAPSHOT'
}
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
ext 라는 키워드는 build.gradle에서 사용하는 전역변수를 설정하겠다는 의미로
springBootVersion 전역변수를 생성하고 그 값을 ‘2.4.2-SNAPSHOT’로 설정한 것이다.
즉 spring-boot-gradle-plugin라는 스프링 부트 그레들 플러그인의 2.4.2-SNAPSHOT를 의존성으로 받겠다는 의미이다.
플러그인 의존성들을 적용할 것인지 결정
plugins {
id 'org.springframework.boot'
id 'io.spring.dependency-management'
id 'java'
}
io.spring.dependency-management
플러그인은 스프링 부트의 의존성들을 관리해 주는 플러그인이라 꼭 추가해야 한다.
각종 의존성(라이브러리)들을 어떤 원격 저장소에서 받을지
repositories {
mavenCentral()
jcenter()
}
기본적으로 mavenCentral을 많이 사용하지만, 최근에는 라이브러리 업로드 난이도 때문에 jcenter도 많이 사용한다.
jcenter에 라이브러리를 업로드하면 mavenCentral에도 업로드될 수 있도록 자동화를 할 수 있습니다.
프로젝트 개발에 필요한 의존성들을 선언
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
특정 버전을 명시하면 안됩니다. 버전을 명시하지 않아야만 맨 위에 작성한
‘org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}’의 버전을 따라가게 된다.
이렇게 관리할 경우 각 라이브러리들의 버전 관리가 한 곳에 집중되고, 버전 충돌 문제도 해결되어 편하게 개발을 진행할 수 있다.
implementation을 사용한 이유는 공식 문서와 구글링을 참고했고, 간단하게 요약해보면 다음과 같은 이유이다.
implementation을 사용한 이유
(1) 의존성 옵션
gradle 프로젝트는 여러 모듈을 포함할 수 있고 하나의 모듈은 다른 모듈을 의존할 수 있다.
모듈이 커지면 빌드 시간이 오래 걸리고 여러 모듈이 많이 얽혀 있을수록 빌드 시간이 오래 걸린다.
Gradle 3.0 부터 의존 라이브러리 수정 시 재빌드가 필요한 라이브러리를 선택적으로 할 수 있도록
compile 대신 api 와 implementation 으로 나눠 필요없는 경우 재빌드 하지 않도록 한다.
(2) api와 implementation 차이
-
api : 의존 라이브러리 수정 시 본 모듈을 의존하고 있는 모듈들 또한 재빌드
A(api) <- B <- C
의 경우 C에서 A를 접근할 수 있음
A 수정 시 B와 C 모두 재빌드
-
implementation: 의존 라이브러리 수정 시 본 모듈까지만 재빌드
A(implementation) <- B <- C
의 경우 C에서 A를 접근할 수 없음
A 수정 시 B까지 재빌드
implementation은 dependency 가 compile classpath 에 들어가지 않아서
transitive dependency 를 실수로 depend 하지 않는다.
더 빠른 compile 이 가능하고, dependency change 가 발생했을 때 recompile 을 적게 한다. 쉬운 배포가 가능하다.
(3) 의존성 옵션들
-
implementation
의존 라이브러리 수정시 본 모듈까지만 재빌드
본 모듈을 의존하는 모듈은 해당 라이브러리의 api 를 사용할 수 없음
-
api
의존 라이브러리 수정시 본 모듈을 의존하는 모듈들도 재빌드
본 모듈을 의존하는 모듈들도 해당 라이브러리의 api 를 사용할 수 있음
-
compileOnly
compile 시에만 빌드하고 빌드 결과물에는 포함하지 않음
runtime 시 필요없는 라이브러리인 경우 (runtime 환경에 이미 라이브러리가 제공되고 있는가 하는 등의 경우)
참고: https://blog.gradle.org/introducing-compile-only-dependencies
-
runtimeOnly
runtime 시에만 필요한 라이브러리인 경우
-
annotationProcessor
annotation processor 명시 (gradle 4.6)