[Gradle] runtimeOnly, implementation, compileOnly, api 차이
classpath
우선 가장 먼저 classpath의 개념과 종류를 알아보자.
classpath는 클래스나 jar 파일이 존재하는 위치다. JVM이 프로그램을 실행할 때, 클래스 파일을 찾는데 기준이 되는 경로를 말한다.
compileClassPath vs runtimeClassPath
Gradle 프로젝트의 의존성 관리를 위해 사용되는 두가지 속성이다.
compileClassPath
프로젝트의 소스 코드를 컴파일 하는 동안 필요한 모든 클래스 파일과 라이브러리를 포함한다.
runtimeClassPath
프로젝트를 실행할 때 필요한 모든 클래스 파일과 라이브러리를 포함한다.
초록색은 사용자가 의존성을 선언할 때 사용한다.
분홍색은 구성요소가 라이브러리를 컴파일하거나 실행할 때 사용한다.
파란색은 구성 요소 자체 사용을 위해 구성 요소 내부에서 사용한다.
차이 비교
runtimeOnly
라이브러리가 런타임에만 필요하다는것을 나타낸다. 프로젝트 빌드 시점에 해당 라이브러리를 classpath에 추가하지 않고, 런타임에 필요한 경우에만 라이브러리를 프로젝트에 포함한다.
compileOnly
라이브러리가 컴파일 시점에만 필요하다는 것을 나타낸다. 프로젝트의 빌드 시점에 해당 라이브러리를 컴파일에 사용하고, 빌드된 결과물에는 포함하지 않는다. 컴파일 시점에서만 해당 라이브러리를 참고 가능하다.
implementation
라이브러리가 컴파일 및 런타임 시점에 모두 필요하다는 것을 나타낸다. 프로젝트의 compileClasspath 및 runtimeClassPath 양쪽에 모두 포함된다.
이 옵션을 사용하면 프로젝트 빌드 시점에 해당 라이브러리를 컴파일에 사용하고, 빌드된 결과물에도 포함한다. 라이브러리와 관련된 클래스 및 메서드를 프로젝트에서 직접 참고한다.
의존 라이브러리 수정 시 본 모듈까지만 재빌드 한다.
api
라이브러리가 컴파일 및 런타임 시점에 모두 필요하다는 것을 나타낸다. 프로젝트의 compileClasspath 및 runtimeClassPath 양쪽에 모두 포함된다.
✔️ implementation vs api
이 두개는 다른 모듈이 의존했을때 차이가 나타난다.
📌 api를 사용해 라이브러리를 가져올 경우
모듈에서 api를 사용해 라이브러리를 가져오게 되면, 해당 라이브러리는 해당 모듈을 의존하는 모듈에도 가져와진다.
ModuleA에서 api를 사용해 라이브러리를 가져온 다음 ModuleB에서 api를 사용해 ModuleA를 가져올 경우 라이브러리도 같이 가져와진다.
두개의 프로젝트 A,B가 있다고 가정하자. A 프로젝트가 B 프로젝트를 의존하면 B 프로젝트에서 api로 선언된 라이브러리도 B 프로젝트의 종속성으로 포함이 된다. 그렇기에 api 종속성은 다른 프로젝트와 공유되며, 라이브러리의 공개 api로 간주된다.
📌 implementaition을 사용해 라이브러리를 가져올 경우
모듈에서 implementation을 사용해 가져오는 라이브러리는 해당 모듈을 의존하는 모듈에는 가져와지지 않는다.
ModuleA에서 implementation을 이용해 Library를 가져온다음 ModuleB에서 implementation을 사용해 moduleA를 가져오면 Library는 가져와지지 않는다. Library는 ModuleA에 캡슐화되어 ModuleB에 노출되지 않는다.
내가 정의한 클래스는 C이고 외부 라이브러리 B를 호출한 상황이라고 가정해보자. 의존성 방향은 C→B→A 이다.
B를 implementation으로 선언했을 경우, compilePath에는 B만 들어가게 된다. C를 정의한 사용자 입장에서는 A를 알 수 없고, A가 수정이 되면 A를 직접적으로 의존하는 모듈인 B까지만 rebuild하면 된다.
그러나, B를 api로 선언했을 경우 compilePath에 A도 들어가게 된다. 컴파일 타임에서 A까지 알아야 하는 상황이다. A가 수정이 돼서 재빌드를 해야하면 C까지도 빌드를 해줘야 한다.
그래서 implementation을 사용하는 경우엔 다음과 같은 장점이 있다.
- 직접적으로 의존하는 모듈까지만 rebuild 해주기 때문에 빠르다.
- API 노출을 막는다(사용자에게 필요 이상의 API를 노출하는 것을 불필요하기 때문이다.)