Computer Science/Etc

Gradle의 라이브러리 의존성 옵션 정리

TwinParadox 2021. 10. 4. 11:33
728x90

익숙함

문득 웹 프로젝트 관련 내용들을 정리해나가면서, gradle 파일을 보니까 다음과 같은 부분이 눈에 들어왔다.

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'com.h2database:h2'
	annotationProcessor 'org.projectlombok:lombok'
}

언제부턴가 기존 프로젝트를 따라가는 방식으로 라이브러리 의존성을 작성하다 보니까,

이것들에 대한 이해하고 있다는 확신이 들지 않아 정리가 필요해보여 글로 정리해본다.

 

 

일단 공식 홈페이지부터....

일단 공식 홈페이지의 그림 하나와 표를 가져와보자.

 

Gradle의 Dependency Configuration

 

Java Library Plugin Configuration

 

초록색은 사용자가 의존성을 선언할 때 사용한다.

분홍색은 구성요소가 라이브러리를 컴파일하거나 실행할 때 사용한다.

파란색은 구성 요소 자체 사용을 위해 구성 요소 내부에서 사용한다.

 

그래프를 보면 우리가 궁금해하는 내용은 초록색에 해당하는 내용이지만,

파란색과 분홍색의 내용이 무엇인지 알아야 초록색에 대해서 이해할 수 있다.

 

Java Library Plugin - Configuration use by Consumers

apiElements

라이브러리 컴파일(Compile)

해당 라이브러리를 컴파일하는 데 필요한 모든 요소를 검색할 때 사용한다.

default 설정과 다르게, implemenation이나 runtime 의존성에 대한 정보를 노출하지 않는다.

 

runtimeElements

라이브러리 실행(Runtime)

해당 라이브러리를 실행하는 데 필요한 모든 요소를 검색할 때 사용한다.

 

Java Library plugin - configurations used by the library itself

compileClassPath와 runtimeClassPath는 우리가 알고 있는 그 classPath에 대한 내용이다.

그러면 다시 돌아와서, 아래 표와 그래프의 초록색 요소들에 대해 정리를 해보자.

Java Library plugin - configurations used to declare dependencies

 

api

컴파일 타임과 런타임에 사용자에게 의존성을노출시킨다.

의존 라이브러리가 수정되는 경우 본 모듈을 의존하는 모든 모듈들을 재빌드한다.

 

implementation

내부적으로만 사용되고 사용자에게는 의존성을 노출시키지 않게 선언한다.

다만, 런타임에는 노출된다.

의존 라이브러리를 수정해도 본 모듈까지만 재빌드한다.

 

 

결국, api와 implementation은 다음과 같은 차이를 가진다.

A <= B <= C의 구조를 가지는 모듈이 있다고 가정하자.

  • A가 api면, C에서는 A 접근이 가능하며 A가 수정되면 B, C가 재빌드된다.
  • A가 implemenation이면, C에서 A를 접근할 수 없고 A 수정 시 B까지만 재빌드한다.

 

compileOnly

컴파일 타임에 필요한 라이브러리

컴파일 시에만 빌드하고 빌드 결과물에는 포함하지 않는다.

 

compileOnlyApi

사용자가 만든 모듈에 의해 컴파일 타임에 필요한 라이브러리

compileOnly와 동일하게 컴파일 시에만 빌드하고 빌드 결과물에는 제외된다.

 

runtimeOnly

런타임 시점에만 필요한 라이브러리

 

annotationProcessor

annotation processor를 명시하기 위해 사용

 

 

그래서, 언제 무엇을 써야 하는가?

라이브러리마다 필요한 시점이 다르기 때문에 거기에 맞게 사용해야 한다.

가장 좋은 건 라이브러리마다 어떤 방식으로 제공하는지 이해한 후, 그에 맞게 사용해야 한다.

api는 의존 프로젝트를 전체 재빌들할만한 프로젝트 경험이 없어서 정리할 내용이 없고,

주로 사용하는 것들만 간단하게 정리해봤다.

 

 

implemenation

예전에 안드로이드를 잠깐 맛만 봤을 때 compile이 Deprecated되면서, 대부분의 implementation으로 변경했었다.

실제로 MVNRepository에서 의존성 추가하려고 예시를 가져오면 대부분 이것을 사용한다.

이 옵션은 대규모 빌드에서는 다시 컴파일을 진행할 때, 그 대상의 크기가 줄어 빌드 시간을 개선할 수 있다고 한다.

프로젝트에 어떤 라이브러리를 사용한다고 하면 대부분 이것을 사용하게 된다.

 

compileOnly

컴파일 시점에 꼭 필요한 라이브러리

Lombok 같은 라이브러리가 이에 해당한다.

 

runtimeOnly

컴파일 시점에는 필요 없지만, 런타임에 필요한 라이브러리

Logging 관련 라이브러리, DB 관련 라이브러리 등이 있겠다.

 

 

Reference

https://docs.gradle.org/current/userguide/java_library_plugin.html

https://www.geeksforgeeks.org/how-is-compiletime-classpath-different-from-runtime-classpath-in-java/
https://tomgregory.com/gradle-implementation-vs-compile-dependencies/
https://stackoverflow.com/questions/4270950/compile-time-vs-run-time-dependency-java/4271013
https://stackoverflow.com/questions/44493378/whats-the-difference-between-implementation-and-compile-in-gradle

 

728x90