1. 程式人生 > >【Maven依賴衝突】Maven jar包衝突問題排查及解決方案

【Maven依賴衝突】Maven jar包衝突問題排查及解決方案

前言

寫這篇文章的初衷是因為今天在使用mvn dependency:tree命令時,突然想起一年前面試阿里的一道面試題。面試題是說假設線上發生JAR包衝突,應該怎麼排查?我那時候的回答是IDEA有個Maven Helper的外掛,可以幫忙分析依賴衝突,然後還有一種辦法是如果一個類import的時候提示兩個地方可匯入,那就說明有衝突。現在回頭想想確實太不專業了,以下是一次JAR包衝突的一個比較正規的流程,是通過整理幾篇部落格後總結的希望對大家也有幫助,如果有錯誤的地方也歡迎指出

關於我:http://huangth.com
GitHub地址:https://github.com/RobertoHuang
JAR衝突產生的原因

   Pom.xml
    /    \
  B        C
/  \      /  \
X    Y    X    M

在以上依賴關係中專案除了會引入B、C還會引入X、Y、M的依賴包,但是如果B依賴的X版本會1.0而C依賴的X版本為2.0時,那最後專案使用的到底是X的1.0版本還是2.0版本就無法確定了。這是就要看ClassLoader的載入順序,假設ClassLoader先載入1.0版本那就不會載入2.0版本,反之同理

使用mvn -Dverbose dependency:tree排查衝突

mvn dependency:tree -Dverbose > tree.txt 寫到檔案中

[INFO] +- org.apache.tomcat:tomcat-servlet-api:jar:7.0.70:compile
[INFO] +- org.apache.tomcat:tomcat-jsp-api:jar:7.0.70:compile
[INFO] |  +- org.apache.tomcat:tomcat-el-api:jar:7.0.70:compile
[INFO] |  \- (org.apache.tomcat:tomcat-servlet-api:jar:7.0.70:compile - omitted for duplicate)
[INFO] +- net.sf.jasperreports:jasperreports:jar:5.6.0:compile
[INFO] |  +- (commons-beanutils:commons-beanutils:jar:1.8.0:compile - omitted for conflict with 1.8.3)
[INFO] |  +- commons-collections:commons-collections:jar:3.2.1:compile
[INFO] |  +- commons-digester:commons-digester:jar:2.1:compile
[INFO] |  |  +- (commons-beanutils:commons-beanutils:jar:1.8.3:compile - omitted for duplicate)
[INFO] |  |  \- (commons-logging:commons-logging:jar:1.1.1:compile - omitted for duplicate)


遞迴依賴的關係列的算是比較清楚了,每行都是一個jar包,根據縮排可以看到依賴的關係

最後寫著compile的就是編譯成功的
最後寫著omitted for duplicate的就是有JAR包被重複依賴了,但是JAR包的版本是一樣的
最後寫著omitted for conflict with xx的,說明和別的JAR包版本衝突了,該行的JAR包不會被引入
該命令可配合-Dincludes和-Dexcludes進行使用,只輸出自己感興趣/不感興趣的JAR
引數格式為:[groupId]:[artifactId]:[type]:[version]
每個部分(冒號分割的部分)是支援*萬用字元的,如果要指定多個格式則可以用,分割,如:
mvn dependency:tree -Dincludes=javax.servlet,org.apache.*

解決衝突,使用exclusion標籤將衝突的JAR排除

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>dubbo</artifactId>
  <version>2.8.3.2</version>
  <exclusions>
      <exclusion>
          <artifactId>guava</artifactId>
          <groupId>com.google.guava</groupId>
      </exclusion>
      <exclusion>
          <artifactId>spring</artifactId>
          <groupId>org.springframework</groupId>
      </exclusion>    
  </exclusions>
</dependency>



解決了衝突後的樹(解決衝突的策略是:就近原則,即離根近的依賴被採納)

檢視執行期類來源的JAR包

有時你以為解決了但是偏偏還是報類包衝突,典型症狀是java.lang.ClassNotFoundException或Method不相容等異常,這時你可以設定一個斷點,在斷點處通過下面這個工具類來檢視Class所來源的JAR包

public class ClassLocationUtils {
  public static String where(final Class clazz) {
      if (clazz == null) {
          throw new IllegalArgumentException("null input: cls");
      }
      URL result = null;
      final String clazzAsResource = clazz.getName().replace('.', '/').concat(".class");
      final ProtectionDomain protectionDomain = clazz.getProtectionDomain();
      if (protectionDomain != null) {
          final CodeSource codeSource = protectionDomain.getCodeSource();
          if (codeSource != null) result = codeSource.getLocation();
          if (result != null) {
              if ("file".equals(result.getProtocol())) {
                  try {
                      if (result.toExternalForm().endsWith(".jar") || result.toExternalForm().endsWith(".zip")) {
                          result = new URL("jar:".concat(result.toExternalForm()).concat("!/").concat(clazzAsResource));
                      } else if (new File(result.getFile()).isDirectory()) {
                          result = new URL(result, clazzAsResource);
                      }
                  } catch (MalformedURLException ignore) {

                  }
              }
          }
      }
      if (result == null) {
          final ClassLoader clsLoader = clazz.getClassLoader();
          result = clsLoader != null ? clsLoader.getResource(clazzAsResource) : ClassLoader.getSystemResource(clazzAsResource);
      }
      return result.toString();
  }
}


然後隨便寫一個測試設定好斷點,在執行到斷點出使用ALT+F8動態執行程式碼,如

ClassLocationUtils.where(Logger.class)
1
即可馬上找到對應的JAR,如果這個JAR不是你期望的就說明是IDE快取造成的,清除快取後重試即可

原文:https://blog.csdn.net/RobertoHuang/article/details/81778181?utm_source=copy