Gradle은 Java 프로젝트에서 라이브러리 의존성을 관리하는 데 사용되는 빌드 도구입니다. 프로젝트의 크기와 복잡도에 따라 다양한 라이브러리를 사용하게 되는데, 이러한 라이브러리가 어떻게 프로젝트에 포함되는지 관리하는 것이 매우 중요합니다. 이때 사용되는 것이 바로 Gradle의 다양한 의존성 설정입니다. 이번 글에서는 implementation, compileOnly, developmentOnly, runtimeOnly, annotationProcessor, testImplementation과 같은 의존성 설정의 차이점을 예시와 함께 설명하고, 각 설정을 왜 구분해서 사용해야 하는지도 살펴보겠습니다.
■ 의존성 설정 차이점 정리
설정 | 적용 범위 | 예시 용도 |
implementation | 컴파일 & 런타임 | 일반적인 애플리케이션 라이브러리 |
compileOnly | 컴파일 시점만 | Lombok 같은 애노테이션 라이브러리 |
runtimeOnly | 런타임만 | MySQL 커넥터와 같은 데이터베이스 드라이버 |
annotationProcessor | 컴파일 시점 코드 생성 | Lombok 같은 애노테이션 라이브러리 |
developmentOnly | 개발 환경만 | Spring DevTools 같은 개발 편의 도구 |
testImplementation | 테스트 시점 | JUnit, Mockito와 같은 테스트 프레임워크 |
이처럼 의존성 설정을 구분해서 사용함으로써 빌드 최적화, 의존성 충돌 방지, 최종 빌드 파일 크기 감소 등의 이점을 얻을 수 있습니다. 아래 상세 설명을 살펴보겠습니다.
■ 의존성 설정의 종류
□ □ implementation
- 설명: 컴파일 및 실행 시점 모두에 포함되는 라이브러리 의존성을 지정합니다. 가장 일반적으로 사용하는 설정입니다.
// 예시
implementation 'com.sun.xml.bind:jaxb-impl:2.3.3'
위 설정은 jaxb-impl 라이브러리가 컴파일과 실행 모두에 필요하다는 것을 의미합니다. 이 라이브러리는 컴파일된 바이트코드에 포함되어 실행 시에도 참조됩니다. 그러나, 이 모듈에 의존하는 다른 모듈에게는 노출되지 않습니다.
□ □ compileOnly
- 설명: 컴파일 시점에만 필요한 라이브러리를 지정합니다. 런타임에는 포함되지 않으므로, 컴파일 시 코드의 참조만 필요하고 실제 실행 시에는 필요 없는 라이브러리에 사용됩니다.
// 예시 compileOnly 'org.projectlombok:lombok'
Lombok은 코드에 애노테이션을 적용하여 컴파일 시 자동으로 게터, 세터 등의 메서드를 생성하는데, 이 작업은 컴파일 시점에만 필요하며 런타임에는 필요하지 않습니다. 따라서 compileOnly를 통해 Lombok을 추가합니다.
□ □ runtimeOnly
- 설명: 런타임에만 필요한 라이브러리를 지정합니다. 컴파일 시점에는 필요하지 않지만, 실행 시점에 참조해야 하는 경우에 사용됩니다.
// 예시
runtimeOnly 'com.mysql:mysql-connector-j'
MySQL 커넥터는 애플리케이션이 실행될 때 데이터베이스와 통신하는 데 필요합니다. 컴파일 시점에는 불필요하므로 runtimeOnly로 지정합니다.
□ □ annotationProcessor
- 설명: 컴파일 시점에 애노테이션 프로세서를 사용하여 코드를 생성하거나 변환해야 할 때 사용됩니다.
// 예시
annotationProcessor 'org.projectlombok:lombok'
Lombok은 @Getter, @Setter와 같은 애노테이션을 통해 컴파일 시점에 코드를 자동으로 생성합니다. 이를 위해 annotationProcessor 설정을 통해 Lombok을 등록해야 합니다.
□ □ developmentOnly
- 설명: 개발 환경에서만 필요한 라이브러리를 지정합니다. 프로덕션 빌드에는 포함되지 않습니다.
// 예시
developmentOnly 'org.springframework.boot:spring-boot-devtools'
개발 중에만 필요한 spring-boot-devtools는 핫 리로딩이나 디버깅에 유용합니다. 하지만 프로덕션 환경에서는 필요하지 않기 때문에 developmentOnly로 지정하여 개발 시에만 적용되도록 합니다.
□ □ testImplementation
- 설명: 테스트 코드를 작성할 때만 필요한 라이브러리를 지정합니다.
// 예시
testImplementation 'org.springframework.boot:spring-boot-starter-test'
이 설정을 통해 JUnit과 Mockito 같은 라이브러리를 테스트 시점에만 포함할 수 있습니다.
■ 왜 compileOnly와 runtimeOnly를 사용하지 않고 implementation으로만 사용할 수 없을까?
Gradle에서는 모든 의존성을 implementation으로 지정할 수 있지만, 이렇게 하면 다양한 문제점이 발생합니다.
1. 비효율적인 빌드
- compileOnly는 컴파일 시점에만 필요한 의존성을 지정하는 데 사용됩니다. 이 설정을 사용하면 런타임에 불필요한 라이브러리가 포함되지 않도록 관리할 수 있습니다.
- 예시: Lombok은 컴파일 시점에 애노테이션을 기반으로 코드를 생성하는데, 컴파일 이후에는 더 이상 필요하지 않습니다. 만약 Lombok을 implementation으로 지정하면, 런타임 시에도 Lombok이 포함되어 최종 빌드 파일의 크기가 커지고 메모리 사용량이 증가하게 됩니다.
- runtimeOnly는 런타임에만 필요한 라이브러리를 지정합니다. 이를 사용하지 않고 implementation으로 모두 지정하면, 컴파일 시점에 불필요한 라이브러리도 포함되게 됩니다. 이는 프로젝트의 초기화 시간과 빌드 시간을 증가시킬 수 있습니다.
2. 의존성 충돌 및 관리의 복잡성 증가
- 프로젝트의 규모가 커질수록 의존성 관리가 복잡해집니다. 모든 라이브러리를 implementation으로 지정할 경우, 서로 의존성이 겹치거나 충돌할 가능성이 높아집니다.
- 예를 들어, A 모듈에서 implementation으로 추가한 라이브러리가 B 모듈에도 전이되어 의도치 않게 의존성이 전파될 수 있습니다. 반면에, compileOnly나 runtimeOnly를 사용하면 의존성이 명확히 관리되어, 프로젝트 모듈 간의 의존성 오염을 방지할 수 있습니다.
3. 최종 빌드 크기 증가
- 모든 의존성을 implementation으로 지정하면, 최종 빌드된 JAR 또는 WAR 파일에 불필요한 라이브러리가 포함될 수 있습니다. 이는 배포 파일의 크기를 증가시키고, 로딩 시간 및 배포 시간에도 영향을 줍니다.
- compileOnly를 통해 컴파일 시점에만 필요한 라이브러리를 분리하면, 최종 애플리케이션 빌드 크기를 줄일 수 있어 효율적인 배포와 성능 최적화가 가능합니다.
'Java' 카테고리의 다른 글
[S3] Spring에서 AWS S3 설정을 활용한 파일 업로드 (1) | 2024.11.08 |
---|---|
[Gradle] 의존성 설정과 컴파일/런타임 시점의 이해(feat.Lombok) (0) | 2024.09.30 |
[JUnit]Spring Boot에서 JUnit으로 테스트하는 방법 (1) | 2024.09.09 |
[JWT] Spring Boot에서 JWT(Json Web Token) 적용하기 (0) | 2024.09.04 |
[Spring] 왜 자주 사용하는 객체들을 자동으로 빈으로 등록하지 않을까? (0) | 2024.08.30 |