1️⃣ Gradle Plugin
Java Plugin이란?
Gradle을 이용해 Java 또는 Spring 프로젝트를 구성할 때 build.gradle 파일의 dependency 영역에 필요로 하는 라이브러리와 프레임워크의 의존성을 주입받는다.
repositories {
mavenCentral()
}
dependencies {
implementation "org.projectlombok:lombok"
annotationProcessor "org.projectlombok:lombok"
testImplementation "org.projectlombok:lombok"
testAnnotationProcessor "org.projectlombok:lombok"
}
해당 포맷으로 필요로하는 의존성을 작성하면 Maven Central Repository에 등록되어 있는 jar 파일을 다운받아 프로젝트에 의존성을 주입받는 것이다.
하지만 의존성 주입을 위해 설정할 것이 한가지 더 있다. Gradle에서 Java 프로젝트를 빌드하기 위해서는 명시적으로 Java Plugin을 사용한다고 설정을 해야한다.
plugins {
id 'java'
}
Java Plugin 설정 시 아래의 내용들을 제공한다.
- 자바 소스 코드를 컴파일한다.
- JUnit(Default) 테스트를 실행한다.
- 컴파일 된 클래스와 리소스 파일(resources)를 포함해 Java 애플리케이션을 배포 가능한 형태(JAR)로 패키징한다.
- 자바 소스 코드와 테스트 코드를 저장하는 디렉토리를 설정한다.
이 디렉토리들은 빌드 도구(Gradle, Maven 등)에서 소스 코드와 테스트 코드를 올바르게 인식하고 처리할 수 있도록 지정된다. - 프로젝트 의존성을 지정한다.
Java-Library Plugin이란?
plugins {
id 'java-library'
}
Java-Library Plugin은 기존의 Java Plugin에서 기능을 확장하여 추가적인 기능을 제공하는 플러그인이다. Java Plugin을 확장했기 때문에 Java Plugin에 의해 제공되는 모든 source sets, tasks, configurations를 암시적으로 사용할 수 있다.
또한 Java-Library Plugin 사용 시 dependency에서 api 옵션을 사용할 수 있다는 차이가 있다.
dependencies {
// JWT
api 'io.jsonwebtoken:jjwt-api:0.12.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5'
}
2️⃣ 의존성 옵션
클래스 패스(class path)
자바로 작성된 프로그램은 자바 컴파일러가 Java 파일들을 컴파일하여 바이트 코드(.class)로 만들고, 이를 JVM의 클래스로더가 읽어들여 애플리케이션이 실행 시 바이트 코드를 기계어로 번역한다. 자바 런타임 환경에서 자바 애플리케이션을 컴파일(compile)하고 실행(run)할 때, 자바 컴파일러와 JVM이 특정 경로에서부터 클래스 파일과 패키지를 탐색하게 되는데 이를 클래스 패스(class path)라고 한다.
자바 컴파일 시 탐색하는 경로와 실행 시 탐색하는 경로를 각각 compile class path, runtime class path라고 한다.
🫧 Compile Classpath
- java 코드를 class 파일로 컴파일할 때 탐색하는 경로이다.
- 에러 없이 컴파일을 하기 위해 필요한 클래스와 jar들의 경로를 나타낸다.
- 따라서 해당 부분만 잘 설정했다고 해서 애플리케이션이 잘 작동하는 것을 보장하지는 않는다.
런타임에서 필요한 다른 클래스와 jar가 필요할 수 있기 때문이다.
🫧 Runtime Classpath
- 애플리케이션이 정상적으로 실행하기 위해 필요한 클래스들과 jar들의 경로를 나타낸다.
- 컴파일된 자바 코드(class 파일)을 JVM이 실행할 때 탐색하는 경로이다.
의존성 옵션
Gradle에서 의존성을 추가할 때 옵션을 통해 컴파일 시점, 실행 시점 중 어느 범위로 노출시킬 것인지 결정할 수 있다.
- compileOnly: 컴파일 경로에만 설정
- runtimeOnly: 런타임 경로에만 설정
- implementation: 두 경로에 모두 설정
- api: 두 경로에 모두 설정
아래 다이어그램으로 해당 옵션들이 어느 범위까지 의존성 구성을 하는지 확인할 수 있다.
3️⃣ implementation vs api
전이 의존성 또는 추이 의존성(Transitive Dependency)이란?
예를 들어 위와 같이 Project C는 B에 의존하고, B는 A에 의존할 경우, Project C도 A에 의존하게 되는 것을 전이 의존성 또는 추이 의존성이라고 한다.
implementation과 api 차이
api는 전이 의존성을 허용한다.
예를 들어 Project C가 implementation을 통해 B에 의존하고, B가 api를 사용하여 A에 의존할 경우 Project C는 implementation을 통해 Project B의 컴파일 경로, 런타임 경로 등이 노출됨과 동시에 Project B의 api의 전이 의존성을 통해 Project A도 사용 가능하다.
하지만 implementation의 경우 전이 의존성이 허용되지 않는다.
위의 경우 Project B에서 implementation을 사용하여 A에 의존하고 있으므로, Project C에서 A의 코드에 접근이 불가능하다. 만약 A의 코드에 접근을 시도할 경우 컴파일 에러가 발생한다.
아래는 이를 응용한 몇가지 사례이다.
각각 어떨 때 사용해야 할까?
우선 implementation과 api의 장점에 대해 알아보자
implementation 장점
- 은닉성 유지
프로젝트의 내부 구현을 다른 모듈과 분리하여 은닉할 수 있어 외부에 불필요한 의존성을 노출시키지 않고 모듈을 보다 깔끔하게 유지할 수 있도록 도와준다. - 컴파일 타임 최적화
implementation으로 선언된 의존성은 컴파일 타임에만 필요하므로, 프로젝트 빌드 속도를 높일 수 있다. 이는 불필요한 의존성이 런타임에 모듈에 포함되지 않아야 할 때 유용하다.
api 장점
- 외부 모듈에 공개
다른 모듈이 해당 의존성을 사용할 수 있으므로, API로 제공되는 기능을 외부에 공개하고 활용할 수 있다. - 동적한 모듈 간 의존성 관리
api로 선언된 의존성은 다른 모듈이 직접적으로 사용할 수 있으므로, 모듈 간의 의존성 관리가 더욱 동적으로 이루어질 수 있다.
멀티 모듈 프로젝트에 api를 사용할 경우 실수로 전이 종속성에 빠질 수 있기 때문에 가능한 implementation을 사용하는 것이 좋다. implementation을 사용하면 모듈을 사용하는 곳의 컴파일 클래스 경로에서 종속성을 유지할 수 있고, implementation으로 선언된 라이브러리가 사용되려고 할 때 컴파일 에러가 발생하여 프로젝트의 구조와 의존성을 명확하게 관리하고 의도치 않은 의존성이 노출되는 것을 방지할 수 있다.
📚 참고
'Back-end' 카테고리의 다른 글
[Spring] Spring Security를 이용한 JWT 기반 인증 및 인가 설정 (0) | 2024.06.22 |
---|---|
[Spring Boot] 내가 적용한!!! 멀티 모듈 기준 (0) | 2024.06.12 |
[Spring Boot] 멀티 모듈 참고 영상 및 정리 (0) | 2024.05.17 |
[JPA] JPA Entity에서의 equals(), hashCode() (0) | 2024.05.16 |
Postman 환경변수 자동 세팅(토큰값 자동 세팅) (0) | 2024.05.06 |