본문 바로가기
개발툴

메이븐 버전 충돌 해결

by 탁구치는 개발자 2017. 12. 13.

pom.xml 에 여러 개의 dependency 설정을 했을 때 각 라이브러리가 참조하는 라이브러리 중 버전이 충돌하는 경우가 있다.

예를 들어 다음과 같이 hystrix-core 라이브러리는 commons-logging 1.1.1 버전을 참조하고 있고

httpcomponents 라이브러리는 commons-logging 1.2 버전을 참조한다. 

1
2
hystrix-core -> commons-logging:1.1.1
httpcomponents -> commons-logging:1.2
cs


이처럼 두 개의 서로 다른 버전을 참조하고 있을 때 maven은 root 레벨과 가장 가까운 라이브러리를 선택하게 된다.

이게 무슨 의미냐 하면

mvn dependency:tree 명령을 치면 pom.xml 에 선언되어 있는 의존성 라이브러리들의 트리 구조를 확인할 수 있다.

pom.xml 자신이 root 라고 했을 때 그 안에 선언되어 있는 dependency 들이 트리 구조로 보여진다.

즉, <dependencies> </dependencies> 안에서 가장 위에 있는 <dependency> 가 root 와 가장 가까운 라이브러리라 할 수 있는 것이다.


아래 두 개의 라이브러리가 선언되어 있을 때 해당 프로젝트에서는 commons-logging:1.2 버전이 사용되어 진다. (httpclient 라이브러리가 root 와 가깝기 때문)

1
2
3
4
5
6
7
8
9
10
11
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5</version>
</dependency>
 
<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-core</artifactId>
    <version>1.4.4</version>
</dependency>
cs


이와같이 버전 충돌시 메이븐 버전 전략에 의존하는 것이 아닌 내가 직접 제어하고 싶은 경우가 있다.

개발자가 직접 해결하는 방법에 대해서 작성해 본다.


1. 

maven-enforcer-plugin 설정

pom.xml 파일에 아래 플러그인을 추가한다.

maven-enforcer-plugin 은 버전 충돌이 발생하는 라이브러리를 출력해 준다.

1
2
3
4
5
6
7
8
9
10
11
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-enforcer-plugin</artifactId>
    <version>1.4.1</version>
    <configuration>
        <rules>
            <dependencyConvergence/>
        </rules>
    </configuration>
</plugin>
 
cs

위의 플러그인 설정 후 다음의 명령어를 실행해 보자.

1
mvn enforcer:enforce
cs


pom.xml 에 버전 충돌이 발생하는 라이브러리가 있다면 다음과 같이 출력될 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[WARNING] 
Dependency convergence error for commons-logging:commons-logging:1.1.1 paths to dependency are:
+-test_project:test_project:0.0.1-SNAPSHOT
  +-com.netflix.hystrix:hystrix-core:1.4.4
    +-com.netflix.archaius:archaius-core:0.4.1
      +-commons-configuration:commons-configuration:1.8
        +-commons-logging:commons-logging:1.1.1
and
+-test_project:test_project:0.0.1-SNAPSHOT
  +-org.apache.pdfbox:pdfbox:1.8.10
    +-org.apache.pdfbox:fontbox:1.8.10
      +-commons-logging:commons-logging:1.1.1
and
+-test_project:test_project:0.0.1-SNAPSHOT
  +-org.apache.pdfbox:pdfbox:1.8.10
    +-commons-logging:commons-logging:1.1.1
and
+-test_project:test_project:0.0.1-SNAPSHOT
  +-org.apache.httpcomponents:httpclient:4.5
    +-commons-logging:commons-logging:1.2
and
+-test_project:test_project:0.0.1-SNAPSHOT
  +-org.apache.httpcomponents:fluent-hc:4.5
    +-commons-logging:commons-logging:1.2
cs

프로젝트 내에서 충돌이 발생하는 라이브러리들을 알았으니 이를 해결하기 위한 방법을 알아보자.

2.

해결 방법

가장 쉽게 해결할 수 있는 방법은 exclusion을 버전이 충돌하는 라이브러리에 추가해 주는 것이다.

그럼 hystrix-core는 commons-logging:1.1.1 버전이 아닌 commons-logging:1.2 버전을 사용하게 될 것이다.

1
2
3
4
5
6
7
8
9
10
11
<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-core</artifactId>
    <version>1.4.4</version>
    <exclusions>
    <exclusion>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
    </exclusion>
</exclusions>
</dependency>
cs


허나 난 다른 방법으로 버전 충돌을 해결한다.

일단 충돌이 나는 라이브러리를 모두 추출하고, 충돌나는 라이브러리 중 어떤 버전을 사용할지 결정한다.

commons-logging:1.2, commons-logging:1.1 두 개가 있다고 했을 때 commons-logging:1.2 사용 결정

결정이 되면 다음과 같이 주석으로 충돌이 발생하는 라이브러리라고 표기하고 그 아래에 의존성 라이브러리를 추가한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- ==================================================== -->
<!-- dependency conflict library -->
<!-- ==================================================== -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>18.0</version>
</dependency>
 
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.8.7</version>
</dependency>
 
<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.9.7</version>
</dependency>
cs


마지막으로 충돌이 발생하는 라이브러리에 exclusion을 추가한다.

이와 같이 하면 dependency conflict library 주석 하위에 선언한 라이브러리를 참조하게 될 것이다.

1
2
3
4
5
6
7
8
9
10
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    <exclusions>
        <exclusion>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
        </exclusion>
    </exclusions>
</dependency>
cs


결론은 충돌이 발생하는 라이브러리들이 있다면 충돌이 발생하는 라이브러리를 명시적으로 작성한다.

그리고 선언한 라이브러리들을 사용할 수 있게 충돌이 발생하는 구간에 exclusion 옵션을 추가해 주는 것이다.