본문 바로가기
Study

dependencies의 implementation, api 차이점

by epro 2020. 8. 29.

Gradle 버전업을 하고

최근에 회사에서 주로 쓰는 자바버전을 Open Jdk11로 바꾸면서 이런저런 라이브러리 버전도 같이 올리게 되었다.

Gradle은 6.5.1을 적용했는데, build.gradle을 열어보니 이런 코드가 눈에 띈다.

 

implementation "io.springfox:springfox-swagger2:${swagger_version}"
implementation "io.springfox:springfox-swagger-ui:${swagger_version}"
api "org.springdoc:springdoc-openapi-ui:${springdoc_version}"

 

implementation, api 뭐가 다른건가?

 

Gradle 문서 읽어보기

구글링 해보다가 적당한 문서를 발견할 수 없어서 도큐먼트를 보기로 했다.

 

docs.gradle.org/6.5.1/userguide/dependency_management_for_java_projects.html#sec:configurations_java_tutorial

 

Managing Dependencies of JVM Projects

How does Gradle know where to find the files for external dependencies? Gradle looks for them in a repository. A repository is a collection of modules, organized by group, name and version. Gradle understands different repository types, such as Maven and I

docs.gradle.org

영문문서가 불편하여 허접한 실력이지만 관련된 내용을 한글로 정리해보자.


<Using dependency configurations / 종속성 속성 사용>

Configurations은 dependencies와 artifacts 집합인데, 3가지 주요한 목적이 있다.

1. Declaring dependencies / 종속성 선언
plugin에 정의된 작업을 실행하는데 필요로 하는 subprojects나 외부 artifacts를 쉽게 선언 할 수 있게 해준다.
예로 plugin은 소스 코드를 컴파일 하기 위해 spring web framework를 dependency로 갖는다.
(참고. Gradle plugin은 재사용 가능한 빌드 로직을 패키지화하여 여러 서로다른 프로젝트와 빌드에서 사용할 수 있도록 한 것)

2. Resolving dependencies / 종속성 해결
plugin은 configuration을 사용하여 정의된 작업에 필요한 것을 download 할 수 있다.
예를들어, Maven Central에서 spring web framework의 jar 파일을 다운로드한다.

3. Exposing artifacts for consumption / 사용되는 artifacts 노출
다른 프로젝트들에서 사용할 artifacts들을 정의할 때도 configurations이 사용된다.
예를들어 JAR파일에 패키지 된 컴파일된 소스코드를 사내 Artifactory repository에 퍼블리싱 함.

이 3가지 목적을 염두에 두고, Java 라이브러리 Plugin에 정의된 표준 속성 몇가지를 살펴보겠다.

◻︎ implementation
프로젝트에 드러나있는 api가 아닌데, 그 프로젝트 소스를 컴파일 하는데 의존성이 필요한 것을 표현한다.
예를들어, 내부 persistence layer를 구현하기 위해 Hibernate를 사용하는 프로젝트

◻︎ api
프로젝트에 의해 노출되는 API의 일부인 프로젝트의 프로덕션 소스를 컴파일하는 데 필요한 종속성입니다.
예를 들어 프로젝트는 Guava를 사용하고 메서드 서명에서 Guava 클래스가 있는 공용 인터페이스를 노출합니다.

◻︎ testImplementation
프로젝트의 테스트 소스를 컴파일하고 실행하는 데 필요한 종속성입니다. 
예를 들어 프로젝트는 테스트 프레임 워크 JUnit으로 테스트 코드를 작성한다고 선언합니다.

implementation, api 차이점은 종속성이 있다는 것이 드러나냐, 아니냐의 차이인 것 같다.

근데 뭔가 아리송하고 아직 잘 모르겠다..

 

구글신께서 더 좋은 자료를 찾아주셨다. 제목도 딱 내가 원하던 거네!

https://tomgregory.com/how-to-use-gradle-api-vs-implementation-dependencies-with-the-java-library-plugin/

 

How to use Gradle api vs. implementation dependencies with the Java Library plugin – Tom Gregory

In this article you’ll learn the main differences between Gradle api and implementation configurations with a real-world example showing exactly how things work under the covers. The Java Library Plugin is the recommended plugin to use when building libr

tomgregory.com

이 글에 보면 ABI(Appliation Binary Interface)라는 개념이 나온다.

ABI에 속하는 유형
- public method parameters
- return type
- parent classes or interfaces에 사용되는 유형

ABI에 속하지 않는 유형
- method 본문에서 사용되는 유형
- private method 선언에 정의된 유형

즉, 내가 작성한 Library-A에서 Library-B, Library-C를 참조해서 쓴다고 할 경우,

파라미터나 리턴타입으로 Library-B에 있는 class를 사용했다면, 이건 ABI에 속하는 것이고

private method 내부에서 http call 등을 위해 Library-C를 사용했다면, 그건 Library-A에는 드러나지 않는거라 ABI에 속하지 않는 유형이라고 할 수 있겠다.

        Library-A
                 |
                 |
     |---------------------|

Library-B              Library-C

원문을 보면 그림과 샘플코드를 친절히 첨부해주셔서 이해하기 수월했다.

그럼 이 ABI 개념을 Gradle plugins은 어떻게 풀어냈을까?

그 방법이 바로 api, implementation 이다!

 


api : api의 종속성은 우리가 작성하는 라이브러리의 ABI의 일부이므로 컴파일 및 런타임 클래스 경로에 표시되어야합니다.
implementation : implementation의 종속성은 우리가 작성하는 라이브러리의 ABI의 일부가 아닙니다. 런타임 클래스 경로에만 나타납니다.

ex)
dependencies {
    api 'library-b'
    implementation 'library-c'
}

그래서 이런 dependencies가 생겨난 것이다.

 

근데, 이렇게 써서 무슨 이득이 있는 것인가?

장점은 compileClasspath, runtimeClasspath dependencies를 정확히 표현할 수 있다.

 

일하다 보면, A팀에서 만들어 둔 라이브러리 버전업을 해야하는데, 그 라이브러리가 B팀에서 만든 라이브러리를 참조하고..

또 C 라이브러리 참조하고...

타고, 타고, 타고 들어가다보면 버전 하나 업데이트 하다가 빡치는 경험을 하는 경우가 가~끔 생긴다.

 

여러 라이브러리를 연동하는 어플리케이션을 만드는 경우라면, 권장사항을 따라 만드는 것이 바람직하겠다.

 

댓글