1. 개요

이 사용방법(예제)에서는 Gradle 프로젝트에서 조건부 의존성을 구성하는 방법을 살펴봅니다.

2. 프로젝트 설정

데모를 위해 다중 모듈 프로젝트를 설정할 것입니다. start.spring.io 로 가서 루트 프로젝트 conditional-dependency-demo를 생성해 봅시다 . 우리는 Spring Boot와 함께 Gradle과 Java를 사용할 것입니다.

또한 두 개의 Provider 모듈인 provider1provider2 와 두 개의 소비자 모듈인 consumer1consumer2 를 추가해 보겠습니다 .
조건부 의존성 프로젝트 구조 데모

3. 조건부 의존성 구성

프로젝트 속성을 기반으로 두 Provider 모듈 중 하나를 포함하려고 한다고 가정해 보겠습니다. consumer1 모듈 의 경우 isLocal 속성이 지정된 경우 provider1 모듈을 포함하려고 합니다 . 그렇지 않으면 provider2 모듈이 포함되어야 합니다.

이를 위해 consumer1 모듈 의 gradle.settings.kts  파일 에 다음을 추가해 보겠습니다 .

plugins {
    id("java")
}

group = "com.baeldung.gradle"
version = "0.0.1-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
    testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.7.0")

    if (project.hasProperty("isLocal")) {
        implementation("com.baeldung.gradle:provider1")
    } else {
        implementation("com.baeldung.gradle:provider2")
    }
}

tasks.getByName<Test>("test") {
    useJUnitPlatform()
}

이제 의존성 작업을 실행하여 어떤 Provider 모듈이 선택되는지 확인합니다.

gradle -PisLocal dependencies --configuration implementation
> Task :consumer1:dependencies

------------------------------------------------------------
Project ':consumer1'
------------------------------------------------------------

implementation - Implementation only dependencies for source set 'main'. (n)
\--- com.baeldung.gradle:provider1 (n)

(n) - Not resolved (configuration is not meant to be resolved)

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 591ms
1 actionable task: 1 executed

보시다시피 속성을 전달하면 provider1 모듈이 포함됩니다. 이제 속성을 지정하지 않고 의존성 작업을 실행해 보겠습니다.

gradle dependencies --configuration implementation
> Task :consumer1:dependencies

------------------------------------------------------------
Project ':consumer1'
------------------------------------------------------------

implementation - Implementation only dependencies for source set 'main'. (n)
\--- com.baeldung.gradle:provider2 (n)

(n) - Not resolved (configuration is not meant to be resolved)

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 649ms
1 actionable task: 1 executed

보시 다시피 이제 provider2 가 포함됩니다.

4. 모듈 대체를 통한 조건부 의존성 구성

의존성 대체를 통해 의존성을 조건부로 구성하는 다른 접근 방식을 살펴보겠습니다. consumer2 모듈 의 경우 isLocal 속성이 지정된 경우 provider2 모듈을 포함하려고 합니다 . 그렇지 않으면 모듈 provider1을  사용해야 합니다.

이 목표를 달성하기 위해 다음 구성을 consumer2 모듈 에 추가해 보겠습니다 .

plugins {
    id("java")
}

group = "com.baeldung.gradle"
version = "0.0.1-SNAPSHOT"

repositories {
    mavenCentral()
}

configurations.all {
    resolutionStrategy.dependencySubstitution {
        if (project.hasProperty("isLocal"))
            substitute(project("com.baeldung.gradle:provider1"))
              .using(project(":provider2"))
              .because("Project property override(isLocal).")
    }
}

dependencies {
    implementation(project(":provider1"))

    testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0")
}

tasks.getByName<Test>("test") {
    useJUnitPlatform()
}

이제 동일한 명령을 다시 실행하면 비슷한 결과를 얻을 수 있습니다. 먼저 isLocal 속성을 지정 하여 실행해 보겠습니다 .

gradle -PisLocal dependencies --configuration compilePath
> Task :consumer2:dependencies

------------------------------------------------------------
Project ':consumer2'
------------------------------------------------------------

compileClasspath - Compile classpath for source set 'main'.
\--- project :provider1 -> project :provider2

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

그리고 당연히 provider1 프로젝트가 provider2 프로젝트 로 대체되는 것을 볼 수 있습니다 . 이제 속성을 지정하지 않고 시도해 보겠습니다.

gradle dependencies --configuration compilePath
> Task :consumer2:dependencies

------------------------------------------------------------
Project ':consumer2'
------------------------------------------------------------

compileClasspath - Compile classpath for source set 'main'.
\--- project :provider1

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 623ms
1 actionable task: 1 executed

예상대로 이번에는 대체가 발생하지 않았고 provider1이 포함되었습니다.

5. 두 접근 방식의 차이점

위의 데모에서 보았듯이 두 접근 방식 모두 의존성을 조건부로 구성한다는 목표를 달성하는 데 도움이 되었습니다. 두 접근 방식의 몇 가지 차이점에 대해 이야기해 보겠습니다.

첫째, 조건부 논리를 직접 작성하는 것은 두 번째 접근 방식에 비해 적은 구성으로 더 간단해 보입니다.

둘째, 두 번째 접근 방식에는 더 많은 구성이 포함되지만 더 관용적으로 보입니다. 두 번째 접근 방식에서는 Gradle 자체에서 제공하는 대체 메커니즘을 사용합니다. 또한 교체 이유도 지정할 수 있습니다. 또한 로그에서 이러한 정보를 사용할 수 없는 첫 번째 접근 방식과 달리 대체가 발생하는 것을 확인할 수 있습니다.

compileClasspath - Compile classpath for source set 'main'. 
\--- project :provider1 -> project :provider2

또한 첫 번째 접근 방식에서는 의존성 해결이 필요하지 않았다는 점에 유의하십시오. 다음을 통해 결과를 얻을 수 있습니다.

gradle -PisLocal dependencies --configuration implementation

두 번째 접근 방식에서는 구현 구성을 확인하는 경우 예상한 결과를 볼 수 없습니다. 그 이유는 의존성 해결이 발생할 때만 작동하기 때문입니다. 따라서 다음과 같이 compilePath 구성 에서 사용할 수 있습니다 .

gradle -PisLocal dependencies --configuration compilePath

6. 결론

이것으로 이 글을 마칠 수 있다. 이 기사에서는 Gradle에서 의존성을 조건부로 구성하는 두 가지 접근 방식을 살펴보았습니다. 우리는 또한 둘 사이의 차이점을 분석했습니다.

Gradle과 함께 제공되는 의존성 대체 구성은 보다 관용적인 접근 방식인 것으로 보입니다. 항상 그렇듯이 전체 코드 및 Gradle 구성은 GitHub에서 사용할 수 있습니다 .

res – REST with Spring (eBook) (everywhere)