Mục lục
Trong bài viết này chúng ta sẽ cùng nhau tìm hiểu cách hoạt động của các dependency trong Maven và cách xử lý trong khi xảy ra các xung đột giữa các dependency sử dụng trong project.
Maven dependency tree
Trong Maven chúng ta có thể sử dụng command-line mvn dependency:tree để in ra tất cả các dependency trong project dưới dạng Tree.
Giả sử chúng ta có một project sử dụng các dependency sau
<dependencies> <dependency> <groupId>org.junit.platform</groupId> <artifactId>junit-platform-runner</artifactId> <version>1.2.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>5.2.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>2.19.0</version> <scope>test</scope> </dependency> <!-- TestNG Dependencies --> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.14.3</version> <scope>test</scope> </dependency> </dependencies>
Khi chúng ta thực thi lệnh mvn dependency:tree thì sẽ có kết quả tương tự như sau
C:\Projects\learns\dependency-resolve-conflicts>mvn dependency:tree [INFO] Scanning for projects... [INFO] [INFO] --------------< org.example:dependency-resolve-conflicts >-------------- [INFO] Building dependency-resolve-conflicts 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ dependency-resolve-conflicts --- [INFO] org.example:dependency-resolve-conflicts:jar:1.0-SNAPSHOT [INFO] +- org.junit.platform:junit-platform-runner:jar:1.2.0:test [INFO] | +- org.apiguardian:apiguardian-api:jar:1.0.0:test [INFO] | +- org.junit.platform:junit-platform-launcher:jar:1.2.0:test [INFO] | +- org.junit.platform:junit-platform-suite-api:jar:1.2.0:test [INFO] | | \- org.junit.platform:junit-platform-commons:jar:1.2.0:test [INFO] | \- junit:junit:jar:4.12:test [INFO] | \- org.hamcrest:hamcrest-core:jar:1.3:test [INFO] +- org.junit.jupiter:junit-jupiter-engine:jar:5.2.0:test [INFO] | +- org.junit.platform:junit-platform-engine:jar:1.2.0:test [INFO] | | \- org.opentest4j:opentest4j:jar:1.1.0:test [INFO] | \- org.junit.jupiter:junit-jupiter-api:jar:5.2.0:test [INFO] +- org.mockito:mockito-junit-jupiter:jar:2.19.0:test [INFO] | \- org.mockito:mockito-core:jar:2.19.0:test [INFO] | +- net.bytebuddy:byte-buddy:jar:1.8.10:test [INFO] | +- net.bytebuddy:byte-buddy-agent:jar:1.8.10:test [INFO] | \- org.objenesis:objenesis:jar:2.6:test [INFO] \- org.testng:testng:jar:6.14.3:test [INFO] +- com.beust:jcommander:jar:1.72:test [INFO] \- org.apache-extras.beanshell:bsh:jar:2.0b6:test [INFO] ------------------------------------------------------------------------
Cách loại bỏ một dependency trong Maven
Nhìn vào kết quả trên chúng ta có thể thấy rằng Junit-4 được sử dụng như một transitive dependency của junit-platform-runner dependency. Nếu đang muốn sử dụng phiên bản mới nhất Junit-5 cho project của mình thì việc loại bỏ Junit-4 ra khỏi project là điều cần thiết.
Để loại bỏ một transitive dependency chúng ta có thể sử dụng exclusions tag trong Maven.
<dependency> <groupId>org.junit.platform</groupId> <artifactId>junit-platform-runner</artifactId> <version>1.2.0</version> <scope>test</scope> <exclusions> <exclusion> <groupId>junit</groupId> <artifactId>junit</artifactId> </exclusion> </exclusions> </dependency>
Bây giờ thực thi lại thì chúng ta sẽ không thấy Junit-4 trong kết quả trả về.
C:\Projects\learns\dependency-resolve-conflicts>mvn dependency:tree [INFO] Scanning for projects... [INFO] [INFO] --------------< org.example:dependency-resolve-conflicts >-------------- [INFO] Building dependency-resolve-conflicts 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ dependency-resolve-conflicts --- [INFO] org.example:dependency-resolve-conflicts:jar:1.0-SNAPSHOT [INFO] +- org.junit.platform:junit-platform-runner:jar:1.2.0:test [INFO] | +- org.apiguardian:apiguardian-api:jar:1.0.0:test [INFO] | +- org.junit.platform:junit-platform-launcher:jar:1.2.0:test [INFO] | \- org.junit.platform:junit-platform-suite-api:jar:1.2.0:test [INFO] | \- org.junit.platform:junit-platform-commons:jar:1.2.0:test [INFO] +- org.junit.jupiter:junit-jupiter-engine:jar:5.2.0:test [INFO] | +- org.junit.platform:junit-platform-engine:jar:1.2.0:test [INFO] | | \- org.opentest4j:opentest4j:jar:1.1.0:test [INFO] | \- org.junit.jupiter:junit-jupiter-api:jar:5.2.0:test [INFO] +- org.mockito:mockito-junit-jupiter:jar:2.19.0:test [INFO] | \- org.mockito:mockito-core:jar:2.19.0:test [INFO] | +- net.bytebuddy:byte-buddy:jar:1.8.10:test [INFO] | +- net.bytebuddy:byte-buddy-agent:jar:1.8.10:test [INFO] | \- org.objenesis:objenesis:jar:2.6:test [INFO] \- org.testng:testng:jar:6.14.3:test [INFO] +- com.beust:jcommander:jar:1.72:test [INFO] \- org.apache-extras.beanshell:bsh:jar:2.0b6:test [INFO] ------------------------------------------------------------------------
Resolve conflicts trong Maven
Trong Maven khi xảy ra các xung đột, có nhiều hơn 1 phiên bản của một dependency được sử dụng trong Project mặc định phiên bản mới hơn sẽ được chọn. Việc này có thể gây ảnh hưởng nếu mã nguồn của bạn đang dựa theo một phiên bản nhất định có thể không phải là phiên bản mới hơn.
Để kiểm tra những dependency nào đang bị xung đột chúng ta có thể sử dụng command-line: mvn dependency:tree -Dverbose để xem.
C:\Projects\learns\dependency-resolve-conflicts>mvn dependency:tree -Dverbose [INFO] Scanning for projects... [INFO] [INFO] --------------< org.example:dependency-resolve-conflicts >-------------- [INFO] Building dependency-resolve-conflicts 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ dependency-resolve-conflicts --- [INFO] org.example:dependency-resolve-conflicts:jar:1.0-SNAPSHOT [INFO] +- org.junit.platform:junit-platform-runner:jar:1.2.0:test [INFO] | +- org.apiguardian:apiguardian-api:jar:1.0.0:test [INFO] | +- org.junit.platform:junit-platform-launcher:jar:1.2.0:test [INFO] | | +- (org.apiguardian:apiguardian-api:jar:1.0.0:test - omitted for duplicate) [INFO] | | \- (org.junit.platform:junit-platform-engine:jar:1.2.0:test - omitted for duplicate) [INFO] | \- org.junit.platform:junit-platform-suite-api:jar:1.2.0:test [INFO] | +- (org.apiguardian:apiguardian-api:jar:1.0.0:test - omitted for duplicate) [INFO] | \- org.junit.platform:junit-platform-commons:jar:1.2.0:test [INFO] | \- (org.apiguardian:apiguardian-api:jar:1.0.0:test - omitted for duplicate) [INFO] +- org.junit.jupiter:junit-jupiter-engine:jar:5.2.0:test [INFO] | +- (org.apiguardian:apiguardian-api:jar:1.0.0:test - omitted for duplicate) [INFO] | +- org.junit.platform:junit-platform-engine:jar:1.2.0:test [INFO] | | +- (org.apiguardian:apiguardian-api:jar:1.0.0:test - omitted for duplicate) [INFO] | | +- (org.junit.platform:junit-platform-commons:jar:1.2.0:test - omitted for duplicate) [INFO] | | \- org.opentest4j:opentest4j:jar:1.1.0:test [INFO] | \- org.junit.jupiter:junit-jupiter-api:jar:5.2.0:test [INFO] | +- (org.apiguardian:apiguardian-api:jar:1.0.0:test - omitted for duplicate) [INFO] | +- (org.opentest4j:opentest4j:jar:1.1.0:test - omitted for duplicate) [INFO] | \- (org.junit.platform:junit-platform-commons:jar:1.2.0:test - omitted for duplicate) [INFO] +- org.mockito:mockito-junit-jupiter:jar:2.19.0:test [INFO] | +- org.mockito:mockito-core:jar:2.19.0:test [INFO] | | +- net.bytebuddy:byte-buddy:jar:1.8.10:test [INFO] | | +- net.bytebuddy:byte-buddy-agent:jar:1.8.10:test [INFO] | | \- org.objenesis:objenesis:jar:2.6:test [INFO] | \- (org.junit.jupiter:junit-jupiter-api:jar:5.1.0:test - omitted for conflict with 5.2.0) [INFO] \- org.testng:testng:jar:6.14.3:test [INFO] +- com.beust:jcommander:jar:1.72:test [INFO] \- org.apache-extras.beanshell:bsh:jar:2.0b6:test [INFO] ------------------------------------------------------------------------
Từ kết quả chúng ta có thể thấy rất nhiều xung đột giữa những dependency trong project trong đó org.junit.jupiter:junit-jupiter-api:jar:5.1.0:test bị loại bỏ do phiên bản 5.2.0 được chọn.
Nếu chúng ta muốn sử dụng junit-jupiter-api 5.1.0 thay vì 5.2.0 thì chúng ta có thêm nó như một dependency chính trong project
<dependencies> .... <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.1.0</version> <scope>test</scope> </dependency> </dependencies>
Kết hợp với exclusions tag ở phần trên, chúng ta có thể quản lý tất cả các dependency mong muốn sử dụng trong project.
Filter trong Maven dependency tree
Nếu dự án Maven đã được phát triển trong một thời gian dài thì chắc hẳn sẽ có nhiều dependency được sử dụng, điều này gây khó khăn cho chúng ta khi muốn tìm kiếm một dependency nhất định. Thật may Maven cung cấp cho chúng ta một số tùy chọn để có thể tìm kiếm trong trường hợp này.
-Dincludes
Chúng ta có thể sử dụng -Dincludes để tìm kiếm một số dependency nhất định. Cú pháp tuân thủ như sau
-Dincludes=[groupId]:[artifactId]:[type]:[version]
Ngoài ra -Dincludes còn hỗ trợ tìm kiếm theo pattern bằng cách thêm dấu * để thay thế các ký tự mà các bạn không nhớ hoặc không muốn ghi ra hết. Ví dụ: org.apache.* Sẽ khớp với tất cả các dependency có id nhóm bắt đầu bằng org.apache.
Ví dụ sau khi thêm junit-jupiter-api 5.1.0 trực tiếp vào file pom.xml. Thì kết quả thực thi sẽ như sau
C:\Projects\learns\dependency-resolve-conflicts>mvn dependency:tree -Dverbose -Dincludes=org.junit.jupiter:junit-jupiter-api [INFO] Scanning for projects... [INFO] [INFO] --------------< org.example:dependency-resolve-conflicts >-------------- [INFO] Building dependency-resolve-conflicts 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ dependency-resolve-conflicts --- [INFO] org.example:dependency-resolve-conflicts:jar:1.0-SNAPSHOT [INFO] +- org.junit.jupiter:junit-jupiter-engine:jar:5.2.0:test [INFO] | \- (org.junit.jupiter:junit-jupiter-api:jar:5.2.0:test - omitted for conflict with 5.1.0) [INFO] +- org.mockito:mockito-junit-jupiter:jar:2.19.0:test [INFO] | \- (org.junit.jupiter:junit-jupiter-api:jar:5.1.0:test - omitted for conflict with 5.2.0) [INFO] \- org.junit.jupiter:junit-jupiter-api:jar:5.1.0:test [INFO] ------------------------------------------------------------------------
Chúng ta có thể thấy junit-jupiter-api:jar:5.1.0 được sử dụng thay cho các phiên bản khác được sử dụng như một transitive dependency trong mockito-junit-jupiter và junit-jupiter-engine dependency.
-Dexcludes
Ngược lại với –Dincludes, -Dexcludes được dùng để loại bỏ một số dependency khỏi kết quả tìm kiếm. -Dexcludes cũng có thể dùng với pattern * hoặc liệt kê nhiều dependency ngăn cách nhau bởi dấu phẩy.
C:\Projects\learns\dependency-resolve-conflicts>mvn dependency:tree -Dexcludes=org.junit.jupiter:junit-jupiter-api [INFO] Scanning for projects... [INFO] [INFO] --------------< org.example:dependency-resolve-conflicts >-------------- [INFO] Building dependency-resolve-conflicts 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ dependency-resolve-conflicts --- [INFO] org.example:dependency-resolve-conflicts:jar:1.0-SNAPSHOT [INFO] +- org.junit.platform:junit-platform-runner:jar:1.2.0:test [INFO] | +- org.apiguardian:apiguardian-api:jar:1.0.0:test [INFO] | +- org.junit.platform:junit-platform-launcher:jar:1.2.0:test [INFO] | \- org.junit.platform:junit-platform-suite-api:jar:1.2.0:test [INFO] +- org.junit.jupiter:junit-jupiter-engine:jar:5.2.0:test [INFO] | \- org.junit.platform:junit-platform-engine:jar:1.2.0:test [INFO] +- org.mockito:mockito-junit-jupiter:jar:2.19.0:test [INFO] | \- org.mockito:mockito-core:jar:2.19.0:test [INFO] | +- net.bytebuddy:byte-buddy:jar:1.8.10:test [INFO] | +- net.bytebuddy:byte-buddy-agent:jar:1.8.10:test [INFO] | \- org.objenesis:objenesis:jar:2.6:test [INFO] +- org.testng:testng:jar:6.14.3:test [INFO] | +- com.beust:jcommander:jar:1.72:test [INFO] | \- org.apache-extras.beanshell:bsh:jar:2.0b6:test [INFO] \- org.junit.jupiter:junit-jupiter-api:jar:5.1.0:test [INFO] +- org.opentest4j:opentest4j:jar:1.0.0:test [INFO] \- org.junit.platform:junit-platform-commons:jar:1.1.0:test [INFO] ------------------------------------------------------------------------
Lưu dependency tree vào file
Chúng ta có thể sử dụng -DoutputFile để lưu dependency tree vào một file được chỉ định.
C:\Projects\learns\dependency-resolve-conflicts>mvn dependency:tree -DoutputFile=dependency-tree.txt [INFO] Scanning for projects... [INFO] [INFO] --------------< org.example:dependency-resolve-conflicts >-------------- [INFO] Building dependency-resolve-conflicts 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ dependency-resolve-conflicts --- [INFO] Wrote dependency tree to: C:\Projects\learns\dependency-resolve-conflicts\dependency-tree.txt [INFO] ------------------------------------------------------------------------
Nguồn: journaldev