国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Maven 3-Maven依賴版本沖突的分析及解決小結(jié)

這篇具有很好參考價(jià)值的文章主要介紹了Maven 3-Maven依賴版本沖突的分析及解決小結(jié)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

舉例
A依賴于B及C,而B又依賴于X、Y,而C依賴于X、M,則A除引B及C的依賴包下,還會(huì)引入X,Y,M的依賴包(一般情況下了,Maven可通過<scope>等若干種方式控制傳遞依賴)。
這里有一個(gè)需要特別注意的,即B和C同時(shí)依賴于X,假設(shè)B依賴于X的1.0版本,而C依賴于X的2.0版本,A究竟依賴于X的1.0還是2.0版本呢?
這就看Classloader的加載順序了,假設(shè)Classloader先加載X_1.0,而它就不會(huì)再加載X_2.0了,如果A恰恰希望使用X_2.0呢,血案就這樣不期而遇了。

?

比如 A 依賴 版本為2.0 的 C ,B 依賴 版本為3.0的 C。在你的pom中,你同時(shí)依賴了 A 和 B ,這時(shí)就會(huì)產(chǎn)生沖突。這時(shí)候你就要判斷,哪個(gè)版本能同時(shí)讓A和B工作(如果可以的話),然后排除掉另一個(gè)就行了。我通常都是排除掉較低的版本。?

<dependencies>  
        <dependency>  
            <groupId>A</groupId>  
            <artifactId>A</artifactId>  
            <version>xxx</version>  
            <exclusions>  
                <exclusion>  
                    <groupId>C</groupId>  
                    <artifactId>C</artifactId>  
                </exclusion>  
            </exclusions>  
        </dependency>  
        <dependency>  
            <groupId>B</groupId>  
            <artifactId>B</artifactId>              
        </dependency>  
</dependencies>  

?

理包依賴是 Maven 核心功能之一,下面通過如何引入 jar 包;如何解析 jar 包依賴;包沖突是如何產(chǎn)生;如何解決包沖突;依賴管理解決什么問題;什么是依賴范圍;使用包依賴的最佳實(shí)踐等 6 個(gè)問題來介紹。

如何引入 jar 包

在代碼開發(fā)時(shí),如果需要使用第三方 jar 包提供的類庫,那么需要在 pom.xml 加入該 jar 包依賴。 例如:使用 zookeeper client

<dependencies>
  <!-- https://mvnrepository.com/artifact/org.apache.hadoop/zookeeper -->
  <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>zookeeper</artifactId>
      <version>3.3.1</version>
  </dependency>
</dependencies>

?

Maven 如何解析 jar 包依賴——傳遞依賴

如上所述,在 pom.xml 中引入 zookeeper jar 包依賴,當(dāng) Maven 解析該依賴時(shí),需要引入的 jar 包不僅僅只有 zookeeper,還會(huì)有 zookeeper 內(nèi)部依賴的 jar 包,還會(huì)有 zookeeper 內(nèi)部依賴的 jar 包依賴的 jar 包......,依賴關(guān)系不斷傳遞,直至沒有依賴。
例如:上述 pom.xml 引入 zookeeper 依賴,實(shí)際引入的 jar 包有

包沖突如何產(chǎn)生?

舉個(gè)?:假設(shè) A->B->C->D1, E->F->D2,D1,D2 分別為 D 的不同版本。
如果 pom.xml 文件中引入了 A 和 E 之后,按照 Maven 傳遞依賴原則,工程內(nèi)需要引入的實(shí)際 Jar 包將會(huì)有:A B C D1 和 E F D2,因此 D1,D2 將會(huì)產(chǎn)生包沖突。

如何解決包沖突

Maven 解析 pom.xml 文件時(shí),同一個(gè) jar 包只會(huì)保留一個(gè),這樣有效的避免因引入兩個(gè) jar 包導(dǎo)致的工程運(yùn)行不穩(wěn)定性。

Maven 默認(rèn)處理策略

  • 最短路徑優(yōu)先
    Maven 面對(duì) D1 和 D2 時(shí),會(huì)默認(rèn)選擇最短路徑的那個(gè) jar 包,即 D2。E->F->D2 比 A->B->C->D1 路徑短 1。
  • 最先聲明優(yōu)先
    如果路徑一樣的話,舉個(gè)?: A->B->C1, E->F->C2 ,兩個(gè)依賴路徑長度都是 2,那么就選擇最先聲明。

移除依賴

如果我們不想通過 A->B->->D1 引入 D1 的話,那么我們?cè)诼暶饕?A 的時(shí)候?qū)?D1 排除掉,這樣也避免了包沖突。
舉個(gè)?:將 zookeeper 的 jline 依賴排除 用exclusions標(biāo)簽

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.3.1</version>
    <exclusions>
        <exclusion>
            <groupId>jline</groupId>
            <artifactId>jline</artifactId>
        </exclusion>
    </exclusions>
</dependency>

?

檢測包沖突工具

mvn dependency:help

mvn dependency:analyze

mvn dependency:tree

mvn dependency:tree -Dverbose

詳細(xì)參考:mvn dependency
mvn dependency:tree

依賴管理解決什么問題

當(dāng)同一個(gè)工程內(nèi)有多個(gè)模塊時(shí),并且要求多個(gè)模塊使用某個(gè) jar 包的相同版本,為了方便統(tǒng)一版本號(hào),升級(jí)版本號(hào),需要提取出一個(gè)父親模塊來管理子模塊共同依賴的 jar 包版本。
舉個(gè)?:有兩個(gè)模塊 projectA, projectB,它們的依賴分別如下所示:
projectA:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-a</artifactId>
      <version>1.0</version>
      <exclusions>
        <exclusion>
          <groupId>group-c</groupId>
          <artifactId>excluded-artifact</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
      <version>1.0</version>
      <type>bar</type>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
</project>

?

projectB:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>group-c</groupId>
      <artifactId>artifact-b</artifactId>
      <version>1.0</version>
      <type>war</type>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
      <version>1.0</version>
      <type>bar</type>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
</project>

?

projectA 和 projectB 共同依賴了 group-a/artifact-b/1.0,提取公共依賴,生成 parent, parent 依賴如下:

<project>
  ...
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>group-a</groupId>
        <artifactId>artifact-b</artifactId>
        <version>1.0</version>
        <type>bar</type>
        <scope>runtime</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

?

則 projectA 和 projectB 均不需要指定 group-a/artifact-b 的 version 信息,未來升級(jí) version 信息時(shí),只需要在 parent 內(nèi)部指定。

projectA:

<project>
  ...
<parent>
<groupId>group-a</groupId>
        <artifactId>artifact-b</artifactId>
        <version>1.0</version>
</parent>
  <dependencies>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-a</artifactId>
      <version>1.0</version>
      <exclusions>
        <exclusion>
          <groupId>group-c</groupId>
          <artifactId>excluded-artifact</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
    </dependency>
  </dependencies>
</project>

?

projectB:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>group-c</groupId>
      <artifactId>artifact-b</artifactId>
      <version>1.0</version>
      <type>war</type>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
    </dependency>
  </dependencies>
</project>

?

依賴范圍

如果不顯示執(zhí)行 <scope> 屬性時(shí),默認(rèn) <scope>compile</scope>。
scope 有哪些屬性:compile, provided, runtime, test, system 等。
詳細(xì)參考:依賴范圍

最佳實(shí)踐

(1)項(xiàng)目中源代碼使用的 jar 包一定在 pom.xml 中顯示引用。
(2)經(jīng)常 check 一下包沖突,檢查是否需要處理。
(3)當(dāng)使用多個(gè)模塊時(shí),parent 一定要使用包管理模塊來規(guī)范 Jar 包版本,而不是包依賴模塊直接引入依賴。 dependencyManagement vs dependencies

?

?

?



?第二個(gè)問題:
第一板斧:找到傳遞依賴的鬼出在哪里?

dependency:tree是把照妖照,pom.xml用它照照,所有傳遞性依賴都將無處遁形,并且會(huì)以層級(jí)樹方式展現(xiàn),非常直觀。

以下就是執(zhí)行dependency:tree后的一個(gè)輸出:
引用

[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ euler-foundation ---
[INFO] com.hsit:euler-foundation:jar:0.9.0.1-SNAPSHOT
[INFO] +- com.rop:rop:jar:1.0.1:compile
[INFO] |  +- org.slf4j:slf4j-api:jar:1.7.5:compile
[INFO] |  +- org.slf4j:slf4j-log4j12:jar:1.7.5:compile
[INFO] |  +- log4j:log4j:jar:1.2.16:compile
[INFO] |  +- commons-lang:commons-lang:jar:2.6:compile
[INFO] |  +- commons-codec:commons-codec:jar:1.6:compile
[INFO] |  +- javax.validation:validation-api:jar:1.0.0.GA:compile
[INFO] |  +- org.hibernate:hibernate-validator:jar:4.2.0.Final:compile
[INFO] |  +- org.codehaus.jackson:jackson-core-asl:jar:1.9.5:compile
[INFO] |  +- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.5:compile
[INFO] |  +- org.codehaus.jackson:jackson-jaxrs:jar:1.9.5:compile
[INFO] |  +- org.codehaus.jackson:jackson-xc:jar:1.9.5:compile
[INFO] |  \- com.fasterxml.jackson.dataformat:jackson-dataformat-xml:jar:2.2.3:compile
[INFO] |     +- com.fasterxml.jackson.core:jackson-core:jar:2.2.3:compile
[INFO] |     +- com.fasterxml.jackson.core:jackson-annotations:jar:2.2.3:compile
[INFO] |     +- com.fasterxml.jackson.core:jackson-databind:jar:2.2.3:compile
[INFO] |     +- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.2.3:compile
[INFO] |     \- org.codehaus.woodstox:stax2-api:jar:3.1.1:compile
[INFO] |        \- javax.xml.stream:stax-api:jar:1.0-2:compile

?




剛才吹噓dependency:tree時(shí),我用到了“無處遁形”,其實(shí)有時(shí)你會(huì)發(fā)現(xiàn)簡單地用dependency:tree往往并不能查看到所有的傳遞依賴。不過如果你真的想要看所有的,必須得加一個(gè)-Dverbose參數(shù),這時(shí)就必定是最全的了。
全是全了,但顯示出來的東西太多,頭暈?zāi)垦?,有沒有好法呢?當(dāng)然有了,加上Dincludes或者Dexcludes說出你喜歡或討厭,dependency:tree就會(huì)幫你過濾出來:
引用

Dincludes=org.springframework:spring-tx

?


過濾串使用groupId:artifactId:version的方式進(jìn)行過濾,可以不寫全啦,如:

mvn dependency:tree -Dverbose -Dincludes=asm:asm  

?



就會(huì)出來asm依賴包的分析信息:

[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ ridge-test ---
[INFO] com.ridge:ridge-test:jar:1.0.2-SNAPSHOT
[INFO] +- asm:asm:jar:3.2:compile
[INFO] \- org.unitils:unitils-dbmaintainer:jar:3.3:compile
[INFO]    \- org.hibernate:hibernate:jar:3.2.5.ga:compile
[INFO]       +- cglib:cglib:jar:2.1_3:compile
[INFO]       |  \- (asm:asm:jar:1.5.3:compile - omitted for conflict with 3.2)
[INFO]       \- (asm:asm:jar:1.5.3:compile - omitted for conflict with 3.2)
[INFO] ------------------------------------------------------------------------

?



對(duì)asm有依賴有一個(gè)直接的依賴(asm:asm:jar:3.2)還有一個(gè)傳遞進(jìn)入的依賴(asm:asm:jar:1.5.3)

第二板斧:將不想要的傳遞依賴剪除掉

承上,假設(shè)我們不希望asm:asm:jar:1.5.3出現(xiàn),根據(jù)分析,我們知道它是經(jīng)由org.unitils:unitils-dbmaintainer:jar:3.3引入的,那么在pom.xml中找到這個(gè)依賴,做其它的調(diào)整:

? ??

<dependency>  
        <groupId>org.unitils</groupId>  
        <artifactId>unitils-dbmaintainer</artifactId>  
        <version>${unitils.version}</version>  
        <exclusions>  
            <exclusion>  
                <artifactId>dbunit</artifactId>  
                <groupId>org.dbunit</groupId>  
            </exclusion>  
            <!-- 這個(gè)就是我們要加的片斷 -->  
            <exclusion>  
                <artifactId>asm</artifactId>  
                <groupId>asm</groupId>  
            </exclusion>  
        </exclusions>  
    </dependency>  

?




再分析一下,你可以看到傳遞依賴沒有了:


    [INFO]  
    [INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ ridge-test ---  
    [INFO] com.ridge:ridge-test:jar:1.0.2-SNAPSHOT  
    [INFO] \- asm:asm:jar:3.2:compile  
    [INFO] ------------------------------------------------------------------------  
    [INFO] BUILD SUCCESS  

?





第三板斧:查看運(yùn)行期類來源的JAR包

有時(shí),你以為解決了,但是偏偏還是報(bào)類包沖突(典型癥狀是java.lang.ClassNotFoundException或Method不兼容等異常),這時(shí)你可以設(shè)置一個(gè)斷點(diǎn),在斷點(diǎn)處通過下面這個(gè)我做的工具類來查看Class所來源的JAR包:

? ?

 package com.ridge.util;  
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.io.File;  
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.net.MalformedURLException;  
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.net.URL;  
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.security.CodeSource;  
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.security.ProtectionDomain;  
  
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> 
 * </span><span style="color: rgba(128, 128, 128, 1)">@author</span><span style="color: rgba(0, 128, 0, 1)"> : chenxh 
 * @date: 13-10-31 
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>  
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ClassLocationUtils {  
  
    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> 
     * 獲取類所有的路徑 
     * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> cls 
     * </span><span style="color: rgba(128, 128, 128, 1)">@return</span> 
     <span style="color: rgba(0, 128, 0, 1)">*/</span>  
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> String where(<span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> Class cls) {  
        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (cls == <span style="color: rgba(0, 0, 255, 1)">null</span>)<span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> IllegalArgumentException("null input: cls"<span style="color: rgba(0, 0, 0, 1)">);  
        URL result </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;  
        </span><span style="color: rgba(0, 0, 255, 1)">final</span> String clsAsResource = cls.getName().replace('.', '/').concat(".class"<span style="color: rgba(0, 0, 0, 1)">);  
        </span><span style="color: rgba(0, 0, 255, 1)">final</span> ProtectionDomain pd =<span style="color: rgba(0, 0, 0, 1)"> cls.getProtectionDomain();  
        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (pd != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {  
            </span><span style="color: rgba(0, 0, 255, 1)">final</span> CodeSource cs =<span style="color: rgba(0, 0, 0, 1)"> pd.getCodeSource();  
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (cs != <span style="color: rgba(0, 0, 255, 1)">null</span>) result =<span style="color: rgba(0, 0, 0, 1)"> cs.getLocation();  
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (result != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {  
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> ("file"<span style="color: rgba(0, 0, 0, 1)">.equals(result.getProtocol())) {  
                    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {  
                        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (result.toExternalForm().endsWith(".jar") ||<span style="color: rgba(0, 0, 0, 1)">  
                                result.toExternalForm().endsWith(</span>".zip"<span style="color: rgba(0, 0, 0, 1)">))  
                            result </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> URL("jar:"<span style="color: rgba(0, 0, 0, 1)">.concat(result.toExternalForm())  
                                    .concat(</span>"!/"<span style="color: rgba(0, 0, 0, 1)">).concat(clsAsResource));  
                        </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> File(result.getFile()).isDirectory())  
                            result </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> URL(result, clsAsResource);  
                    }  
                    </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (MalformedURLException ignore) {}  
                }  
            }  
        }  
        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (result == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {  
            </span><span style="color: rgba(0, 0, 255, 1)">final</span> ClassLoader clsLoader =<span style="color: rgba(0, 0, 0, 1)"> cls.getClassLoader();  
            result </span>= clsLoader != <span style="color: rgba(0, 0, 255, 1)">null</span> ?<span style="color: rgba(0, 0, 0, 1)">  
                    clsLoader.getResource(clsAsResource) :  
                    ClassLoader.getSystemResource(clsAsResource);  
        }  
        </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result.toString();  
    }  
  
}  </span></pre>

?




隨便寫一個(gè)測試,設(shè)置好斷點(diǎn),在執(zhí)行到斷點(diǎn)處按alt+F8動(dòng)態(tài)執(zhí)行代碼(intelij idea),假設(shè)我們輸入:

ClassLocationUtils.where(org.objectweb.asm.ClassVisitor.class)  

?



即可馬上查出類對(duì)應(yīng)的JAR了:

這就是org.objectweb.asm.ClassVisitor類在運(yùn)行期對(duì)應(yīng)的JAR包,如果這個(gè)JAR包版本不是你期望你,就說明是你的IDE緩存造成的,這時(shí)建議你Reimport一下maven列表就可以了,如下所示(idea):

Reimport一下,IDE會(huì)強(qiáng)制根據(jù)新的pom.xml設(shè)置重新分析并加載依賴類包,以得到和pom.xml設(shè)置相同的依賴。(這一步非常重要哦,經(jīng)常項(xiàng)目組pom.xml是相同的,但是就是有些人可以運(yùn)行,有些人不能運(yùn)行,俗稱人品問題,其實(shí)都是IDE的緩存造成的了
idea清除緩存,為了提高效率不建議采用reimport重新起開啟項(xiàng)目的方式,建議采用idea自帶的功能,File->Invalidate Caches 功能直接完成清除idea cache

?

?

?

?

?

?

三、另一個(gè)問題,log沖突:項(xiàng)目中出現(xiàn)的問題如下:

?

Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.apache.log4j.Log4jLoggerFactory

?

后經(jīng)網(wǎng)上搜索加邊上大牛指點(diǎn)發(fā)現(xiàn):

log4j-over-slf4j.jar 和 slf4j-log4j12.jar 在同一個(gè)classpath下就會(huì)出現(xiàn)這個(gè)錯(cuò)誤。

解決方法:?
將slf4j-log4j12.jar從相關(guān)的jar中排除

但是查看maven項(xiàng)目中的pom文件,自己并沒有配置這個(gè)jar的依賴,猜測是maven加載其他jar引入的依賴包。

打開pom.xml文件,在Dependency Hierarchy(依賴列表)中查看jar包的依賴層次關(guān)系。

Maven 3-Maven依賴版本沖突的分析及解決小結(jié)

?

在過濾欄中輸入log4j,右側(cè)出現(xiàn)了log4j相關(guān)包的依賴結(jié)構(gòu),左側(cè)則是pom.xml全部依賴包的列表展示。

直接在右側(cè)選中zookeeper底下的slf4j的jar包,右鍵選擇Exclude,然后保存pom.xml。這樣在加載zookeeper的jar包時(shí)就不會(huì)再加載slf4j的jar包。

Maven 3-Maven依賴版本沖突的分析及解決小結(jié)

修改后對(duì)應(yīng)的dependency文件如下:

?

?
             <dependency>  
    <groupId>org.apache.zookeeper</groupId>  
    <artifactId>zookeeper</artifactId>  
    <version>3.4.6</version>  
    <exclusions>  
        <exclusion>  
            <artifactId>slf4j-log4j12</artifactId>  
            <groupId>org.slf4j</groupId>  
        </exclusion>  
    </exclusions>  
</dependency>  

?


這樣就能通過filter過濾快速找到對(duì)應(yīng)jar,并知道他的依賴關(guān)系,快速解決項(xiàng)目中的jar包沖突問題。?

參考:Maven類包沖突終極解決方案

參考:利用maven工具解決jar包沖突問題或重復(fù)加載問題

參考:Maven 解決jar包沖突的原理

本文來自博客園,作者:aspirant,轉(zhuǎn)載請(qǐng)注明原文鏈接:https://www.cnblogs.com/aspirant/p/8532962.html文章來源地址http://www.zghlxwxcb.cn/news/detail-438163.html

舉例
A依賴于B及C,而B又依賴于X、Y,而C依賴于X、M,則A除引B及C的依賴包下,還會(huì)引入X,Y,M的依賴包(一般情況下了,Maven可通過<scope>等若干種方式控制傳遞依賴)。
這里有一個(gè)需要特別注意的,即B和C同時(shí)依賴于X,假設(shè)B依賴于X的1.0版本,而C依賴于X的2.0版本,A究竟依賴于X的1.0還是2.0版本呢?
這就看Classloader的加載順序了,假設(shè)Classloader先加載X_1.0,而它就不會(huì)再加載X_2.0了,如果A恰恰希望使用X_2.0呢,血案就這樣不期而遇了。

?

比如 A 依賴 版本為2.0 的 C ,B 依賴 版本為3.0的 C。在你的pom中,你同時(shí)依賴了 A 和 B ,這時(shí)就會(huì)產(chǎn)生沖突。這時(shí)候你就要判斷,哪個(gè)版本能同時(shí)讓A和B工作(如果可以的話),然后排除掉另一個(gè)就行了。我通常都是排除掉較低的版本。?

<dependencies>  
        <dependency>  
            <groupId>A</groupId>  
            <artifactId>A</artifactId>  
            <version>xxx</version>  
            <exclusions>  
                <exclusion>  
                    <groupId>C</groupId>  
                    <artifactId>C</artifactId>  
                </exclusion>  
            </exclusions>  
        </dependency>  
        <dependency>  
            <groupId>B</groupId>  
            <artifactId>B</artifactId>              
        </dependency>  
</dependencies>  

?

理包依賴是 Maven 核心功能之一,下面通過如何引入 jar 包;如何解析 jar 包依賴;包沖突是如何產(chǎn)生;如何解決包沖突;依賴管理解決什么問題;什么是依賴范圍;使用包依賴的最佳實(shí)踐等 6 個(gè)問題來介紹。

如何引入 jar 包

在代碼開發(fā)時(shí),如果需要使用第三方 jar 包提供的類庫,那么需要在 pom.xml 加入該 jar 包依賴。 例如:使用 zookeeper client

<dependencies>
  <!-- https://mvnrepository.com/artifact/org.apache.hadoop/zookeeper -->
  <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>zookeeper</artifactId>
      <version>3.3.1</version>
  </dependency>
</dependencies>

?

Maven 如何解析 jar 包依賴——傳遞依賴

如上所述,在 pom.xml 中引入 zookeeper jar 包依賴,當(dāng) Maven 解析該依賴時(shí),需要引入的 jar 包不僅僅只有 zookeeper,還會(huì)有 zookeeper 內(nèi)部依賴的 jar 包,還會(huì)有 zookeeper 內(nèi)部依賴的 jar 包依賴的 jar 包......,依賴關(guān)系不斷傳遞,直至沒有依賴。
例如:上述 pom.xml 引入 zookeeper 依賴,實(shí)際引入的 jar 包有

包沖突如何產(chǎn)生?

舉個(gè)?:假設(shè) A->B->C->D1, E->F->D2,D1,D2 分別為 D 的不同版本。
如果 pom.xml 文件中引入了 A 和 E 之后,按照 Maven 傳遞依賴原則,工程內(nèi)需要引入的實(shí)際 Jar 包將會(huì)有:A B C D1 和 E F D2,因此 D1,D2 將會(huì)產(chǎn)生包沖突。

如何解決包沖突

Maven 解析 pom.xml 文件時(shí),同一個(gè) jar 包只會(huì)保留一個(gè),這樣有效的避免因引入兩個(gè) jar 包導(dǎo)致的工程運(yùn)行不穩(wěn)定性。

Maven 默認(rèn)處理策略

  • 最短路徑優(yōu)先
    Maven 面對(duì) D1 和 D2 時(shí),會(huì)默認(rèn)選擇最短路徑的那個(gè) jar 包,即 D2。E->F->D2 比 A->B->C->D1 路徑短 1。
  • 最先聲明優(yōu)先
    如果路徑一樣的話,舉個(gè)?: A->B->C1, E->F->C2 ,兩個(gè)依賴路徑長度都是 2,那么就選擇最先聲明。

移除依賴

如果我們不想通過 A->B->->D1 引入 D1 的話,那么我們?cè)诼暶饕?A 的時(shí)候?qū)?D1 排除掉,這樣也避免了包沖突。
舉個(gè)?:將 zookeeper 的 jline 依賴排除 用exclusions標(biāo)簽

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.3.1</version>
    <exclusions>
        <exclusion>
            <groupId>jline</groupId>
            <artifactId>jline</artifactId>
        </exclusion>
    </exclusions>
</dependency>

?

檢測包沖突工具

mvn dependency:help

mvn dependency:analyze

mvn dependency:tree

mvn dependency:tree -Dverbose

詳細(xì)參考:mvn dependency
mvn dependency:tree

依賴管理解決什么問題

當(dāng)同一個(gè)工程內(nèi)有多個(gè)模塊時(shí),并且要求多個(gè)模塊使用某個(gè) jar 包的相同版本,為了方便統(tǒng)一版本號(hào),升級(jí)版本號(hào),需要提取出一個(gè)父親模塊來管理子模塊共同依賴的 jar 包版本。
舉個(gè)?:有兩個(gè)模塊 projectA, projectB,它們的依賴分別如下所示:
projectA:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-a</artifactId>
      <version>1.0</version>
      <exclusions>
        <exclusion>
          <groupId>group-c</groupId>
          <artifactId>excluded-artifact</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
      <version>1.0</version>
      <type>bar</type>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
</project>

?

projectB:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>group-c</groupId>
      <artifactId>artifact-b</artifactId>
      <version>1.0</version>
      <type>war</type>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
      <version>1.0</version>
      <type>bar</type>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
</project>

?

projectA 和 projectB 共同依賴了 group-a/artifact-b/1.0,提取公共依賴,生成 parent, parent 依賴如下:

<project>
  ...
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>group-a</groupId>
        <artifactId>artifact-b</artifactId>
        <version>1.0</version>
        <type>bar</type>
        <scope>runtime</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

?

則 projectA 和 projectB 均不需要指定 group-a/artifact-b 的 version 信息,未來升級(jí) version 信息時(shí),只需要在 parent 內(nèi)部指定。

projectA:

<project>
  ...
<parent>
<groupId>group-a</groupId>
        <artifactId>artifact-b</artifactId>
        <version>1.0</version>
</parent>
  <dependencies>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-a</artifactId>
      <version>1.0</version>
      <exclusions>
        <exclusion>
          <groupId>group-c</groupId>
          <artifactId>excluded-artifact</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
    </dependency>
  </dependencies>
</project>

?

projectB:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>group-c</groupId>
      <artifactId>artifact-b</artifactId>
      <version>1.0</version>
      <type>war</type>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
    </dependency>
  </dependencies>
</project>

?

依賴范圍

如果不顯示執(zhí)行 <scope> 屬性時(shí),默認(rèn) <scope>compile</scope>。
scope 有哪些屬性:compile, provided, runtime, test, system 等。
詳細(xì)參考:依賴范圍

最佳實(shí)踐

(1)項(xiàng)目中源代碼使用的 jar 包一定在 pom.xml 中顯示引用。
(2)經(jīng)常 check 一下包沖突,檢查是否需要處理。
(3)當(dāng)使用多個(gè)模塊時(shí),parent 一定要使用包管理模塊來規(guī)范 Jar 包版本,而不是包依賴模塊直接引入依賴。 dependencyManagement vs dependencies

?

?

?



?第二個(gè)問題:
第一板斧:找到傳遞依賴的鬼出在哪里?

dependency:tree是把照妖照,pom.xml用它照照,所有傳遞性依賴都將無處遁形,并且會(huì)以層級(jí)樹方式展現(xiàn),非常直觀。

以下就是執(zhí)行dependency:tree后的一個(gè)輸出:
引用

[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ euler-foundation ---
[INFO] com.hsit:euler-foundation:jar:0.9.0.1-SNAPSHOT
[INFO] +- com.rop:rop:jar:1.0.1:compile
[INFO] |  +- org.slf4j:slf4j-api:jar:1.7.5:compile
[INFO] |  +- org.slf4j:slf4j-log4j12:jar:1.7.5:compile
[INFO] |  +- log4j:log4j:jar:1.2.16:compile
[INFO] |  +- commons-lang:commons-lang:jar:2.6:compile
[INFO] |  +- commons-codec:commons-codec:jar:1.6:compile
[INFO] |  +- javax.validation:validation-api:jar:1.0.0.GA:compile
[INFO] |  +- org.hibernate:hibernate-validator:jar:4.2.0.Final:compile
[INFO] |  +- org.codehaus.jackson:jackson-core-asl:jar:1.9.5:compile
[INFO] |  +- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.5:compile
[INFO] |  +- org.codehaus.jackson:jackson-jaxrs:jar:1.9.5:compile
[INFO] |  +- org.codehaus.jackson:jackson-xc:jar:1.9.5:compile
[INFO] |  \- com.fasterxml.jackson.dataformat:jackson-dataformat-xml:jar:2.2.3:compile
[INFO] |     +- com.fasterxml.jackson.core:jackson-core:jar:2.2.3:compile
[INFO] |     +- com.fasterxml.jackson.core:jackson-annotations:jar:2.2.3:compile
[INFO] |     +- com.fasterxml.jackson.core:jackson-databind:jar:2.2.3:compile
[INFO] |     +- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.2.3:compile
[INFO] |     \- org.codehaus.woodstox:stax2-api:jar:3.1.1:compile
[INFO] |        \- javax.xml.stream:stax-api:jar:1.0-2:compile

?




剛才吹噓dependency:tree時(shí),我用到了“無處遁形”,其實(shí)有時(shí)你會(huì)發(fā)現(xiàn)簡單地用dependency:tree往往并不能查看到所有的傳遞依賴。不過如果你真的想要看所有的,必須得加一個(gè)-Dverbose參數(shù),這時(shí)就必定是最全的了。
全是全了,但顯示出來的東西太多,頭暈?zāi)垦#袥]有好法呢?當(dāng)然有了,加上Dincludes或者Dexcludes說出你喜歡或討厭,dependency:tree就會(huì)幫你過濾出來:
引用

Dincludes=org.springframework:spring-tx

?


過濾串使用groupId:artifactId:version的方式進(jìn)行過濾,可以不寫全啦,如:

mvn dependency:tree -Dverbose -Dincludes=asm:asm  

?



就會(huì)出來asm依賴包的分析信息:

[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ ridge-test ---
[INFO] com.ridge:ridge-test:jar:1.0.2-SNAPSHOT
[INFO] +- asm:asm:jar:3.2:compile
[INFO] \- org.unitils:unitils-dbmaintainer:jar:3.3:compile
[INFO]    \- org.hibernate:hibernate:jar:3.2.5.ga:compile
[INFO]       +- cglib:cglib:jar:2.1_3:compile
[INFO]       |  \- (asm:asm:jar:1.5.3:compile - omitted for conflict with 3.2)
[INFO]       \- (asm:asm:jar:1.5.3:compile - omitted for conflict with 3.2)
[INFO] ------------------------------------------------------------------------

?



對(duì)asm有依賴有一個(gè)直接的依賴(asm:asm:jar:3.2)還有一個(gè)傳遞進(jìn)入的依賴(asm:asm:jar:1.5.3)

第二板斧:將不想要的傳遞依賴剪除掉

承上,假設(shè)我們不希望asm:asm:jar:1.5.3出現(xiàn),根據(jù)分析,我們知道它是經(jīng)由org.unitils:unitils-dbmaintainer:jar:3.3引入的,那么在pom.xml中找到這個(gè)依賴,做其它的調(diào)整:

? ??

<dependency>  
        <groupId>org.unitils</groupId>  
        <artifactId>unitils-dbmaintainer</artifactId>  
        <version>${unitils.version}</version>  
        <exclusions>  
            <exclusion>  
                <artifactId>dbunit</artifactId>  
                <groupId>org.dbunit</groupId>  
            </exclusion>  
            <!-- 這個(gè)就是我們要加的片斷 -->  
            <exclusion>  
                <artifactId>asm</artifactId>  
                <groupId>asm</groupId>  
            </exclusion>  
        </exclusions>  
    </dependency>  

?




再分析一下,你可以看到傳遞依賴沒有了:


    [INFO]  
    [INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ ridge-test ---  
    [INFO] com.ridge:ridge-test:jar:1.0.2-SNAPSHOT  
    [INFO] \- asm:asm:jar:3.2:compile  
    [INFO] ------------------------------------------------------------------------  
    [INFO] BUILD SUCCESS  

?





第三板斧:查看運(yùn)行期類來源的JAR包

有時(shí),你以為解決了,但是偏偏還是報(bào)類包沖突(典型癥狀是java.lang.ClassNotFoundException或Method不兼容等異常),這時(shí)你可以設(shè)置一個(gè)斷點(diǎn),在斷點(diǎn)處通過下面這個(gè)我做的工具類來查看Class所來源的JAR包:

? ?

 package com.ridge.util;  
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.io.File;  
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.net.MalformedURLException;  
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.net.URL;  
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.security.CodeSource;  
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.security.ProtectionDomain;  
  
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> 
 * </span><span style="color: rgba(128, 128, 128, 1)">@author</span><span style="color: rgba(0, 128, 0, 1)"> : chenxh 
 * @date: 13-10-31 
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>  
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ClassLocationUtils {  
  
    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> 
     * 獲取類所有的路徑 
     * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> cls 
     * </span><span style="color: rgba(128, 128, 128, 1)">@return</span> 
     <span style="color: rgba(0, 128, 0, 1)">*/</span>  
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> String where(<span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> Class cls) {  
        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (cls == <span style="color: rgba(0, 0, 255, 1)">null</span>)<span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> IllegalArgumentException("null input: cls"<span style="color: rgba(0, 0, 0, 1)">);  
        URL result </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;  
        </span><span style="color: rgba(0, 0, 255, 1)">final</span> String clsAsResource = cls.getName().replace('.', '/').concat(".class"<span style="color: rgba(0, 0, 0, 1)">);  
        </span><span style="color: rgba(0, 0, 255, 1)">final</span> ProtectionDomain pd =<span style="color: rgba(0, 0, 0, 1)"> cls.getProtectionDomain();  
        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (pd != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {  
            </span><span style="color: rgba(0, 0, 255, 1)">final</span> CodeSource cs =<span style="color: rgba(0, 0, 0, 1)"> pd.getCodeSource();  
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (cs != <span style="color: rgba(0, 0, 255, 1)">null</span>) result =<span style="color: rgba(0, 0, 0, 1)"> cs.getLocation();  
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (result != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {  
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> ("file"<span style="color: rgba(0, 0, 0, 1)">.equals(result.getProtocol())) {  
                    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {  
                        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (result.toExternalForm().endsWith(".jar") ||<span style="color: rgba(0, 0, 0, 1)">  
                                result.toExternalForm().endsWith(</span>".zip"<span style="color: rgba(0, 0, 0, 1)">))  
                            result </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> URL("jar:"<span style="color: rgba(0, 0, 0, 1)">.concat(result.toExternalForm())  
                                    .concat(</span>"!/"<span style="color: rgba(0, 0, 0, 1)">).concat(clsAsResource));  
                        </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> File(result.getFile()).isDirectory())  
                            result </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> URL(result, clsAsResource);  
                    }  
                    </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (MalformedURLException ignore) {}  
                }  
            }  
        }  
        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (result == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {  
            </span><span style="color: rgba(0, 0, 255, 1)">final</span> ClassLoader clsLoader =<span style="color: rgba(0, 0, 0, 1)"> cls.getClassLoader();  
            result </span>= clsLoader != <span style="color: rgba(0, 0, 255, 1)">null</span> ?<span style="color: rgba(0, 0, 0, 1)">  
                    clsLoader.getResource(clsAsResource) :  
                    ClassLoader.getSystemResource(clsAsResource);  
        }  
        </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result.toString();  
    }  
  
}  </span></pre>

?




隨便寫一個(gè)測試,設(shè)置好斷點(diǎn),在執(zhí)行到斷點(diǎn)處按alt+F8動(dòng)態(tài)執(zhí)行代碼(intelij idea),假設(shè)我們輸入:

ClassLocationUtils.where(org.objectweb.asm.ClassVisitor.class)  

?



即可馬上查出類對(duì)應(yīng)的JAR了:

這就是org.objectweb.asm.ClassVisitor類在運(yùn)行期對(duì)應(yīng)的JAR包,如果這個(gè)JAR包版本不是你期望你,就說明是你的IDE緩存造成的,這時(shí)建議你Reimport一下maven列表就可以了,如下所示(idea):

Reimport一下,IDE會(huì)強(qiáng)制根據(jù)新的pom.xml設(shè)置重新分析并加載依賴類包,以得到和pom.xml設(shè)置相同的依賴。(這一步非常重要哦,經(jīng)常項(xiàng)目組pom.xml是相同的,但是就是有些人可以運(yùn)行,有些人不能運(yùn)行,俗稱人品問題,其實(shí)都是IDE的緩存造成的了
idea清除緩存,為了提高效率不建議采用reimport重新起開啟項(xiàng)目的方式,建議采用idea自帶的功能,File->Invalidate Caches 功能直接完成清除idea cache

?

?

?

?

?

?

三、另一個(gè)問題,log沖突:項(xiàng)目中出現(xiàn)的問題如下:

?

Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.apache.log4j.Log4jLoggerFactory

?

后經(jīng)網(wǎng)上搜索加邊上大牛指點(diǎn)發(fā)現(xiàn):

log4j-over-slf4j.jar 和 slf4j-log4j12.jar 在同一個(gè)classpath下就會(huì)出現(xiàn)這個(gè)錯(cuò)誤。

解決方法:?
將slf4j-log4j12.jar從相關(guān)的jar中排除

但是查看maven項(xiàng)目中的pom文件,自己并沒有配置這個(gè)jar的依賴,猜測是maven加載其他jar引入的依賴包。

打開pom.xml文件,在Dependency Hierarchy(依賴列表)中查看jar包的依賴層次關(guān)系。

Maven 3-Maven依賴版本沖突的分析及解決小結(jié)

?

在過濾欄中輸入log4j,右側(cè)出現(xiàn)了log4j相關(guān)包的依賴結(jié)構(gòu),左側(cè)則是pom.xml全部依賴包的列表展示。

直接在右側(cè)選中zookeeper底下的slf4j的jar包,右鍵選擇Exclude,然后保存pom.xml。這樣在加載zookeeper的jar包時(shí)就不會(huì)再加載slf4j的jar包。

Maven 3-Maven依賴版本沖突的分析及解決小結(jié)

修改后對(duì)應(yīng)的dependency文件如下:

?

?
             <dependency>  
    <groupId>org.apache.zookeeper</groupId>  
    <artifactId>zookeeper</artifactId>  
    <version>3.4.6</version>  
    <exclusions>  
        <exclusion>  
            <artifactId>slf4j-log4j12</artifactId>  
            <groupId>org.slf4j</groupId>  
        </exclusion>  
    </exclusions>  
</dependency>  

?


這樣就能通過filter過濾快速找到對(duì)應(yīng)jar,并知道他的依賴關(guān)系,快速解決項(xiàng)目中的jar包沖突問題。?

參考:Maven類包沖突終極解決方案

參考:利用maven工具解決jar包沖突問題或重復(fù)加載問題

參考:Maven 解決jar包沖突的原理

本文來自博客園,作者:aspirant,轉(zhuǎn)載請(qǐng)注明原文鏈接:https://www.cnblogs.com/aspirant/p/8532962.html

到了這里,關(guān)于Maven 3-Maven依賴版本沖突的分析及解決小結(jié)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • java-IDEA MAVEN查看依賴樹,解決jar包重復(fù)和沖突

    java-IDEA MAVEN查看依賴樹,解決jar包重復(fù)和沖突

    ? ?如果這里面的依賴關(guān)系有紅線,就說明有包沖突,一般都是版本不一致,可以在idea里下一個(gè)插件 Maven Helper, 點(diǎn)擊install并重啟IDEA ?打開pom.xml文件,在下方會(huì)出現(xiàn)Dependency Analyzer,選擇它會(huì)出現(xiàn)重復(fù)依賴列表,選擇對(duì)應(yīng)的依賴,右鍵紅色部分選擇Exclude,然后選擇上面的reimport就可

    2024年02月13日
    瀏覽(20)
  • Maven第八章:如何解決Maven的jar版本沖突

    前言 本文重點(diǎn)講解Maven依賴沖突原因,maven依賴原則以及如何利用idea Maven Helper插件分析解決問題。 背景 開發(fā)過程中引入第三方j(luò)ar遇到依賴沖突的,非常影響開發(fā),甚至大部分時(shí)間都在調(diào)試版本兼容。

    2024年02月06日
    瀏覽(22)
  • Maven解決jar包版本沖突的4種方法

    ??先解釋下maven的依賴傳遞:a jar包引入了b jar包,如果項(xiàng)目中引入了a jar包,其實(shí)也會(huì)把a(bǔ)依賴的b jar包引入。那現(xiàn)在有a、c這2個(gè)jar包,a jar包依賴的是1.0.0版本的b jar包,c jar包也依賴了b jar包,版本是2.0.0;如果項(xiàng)目中引入了a、c jar包,那b jar包到底引入哪個(gè)版本呢,是1.0.0還

    2024年02月15日
    瀏覽(16)
  • 【Maven】006-Maven 依賴傳遞和依賴沖突

    【Maven】006-Maven 依賴傳遞和依賴沖突

    概念: Maven 依賴傳遞是指當(dāng)一個(gè)項(xiàng)目依賴于另一個(gè)項(xiàng)目或庫時(shí),Maven 會(huì) 自動(dòng)解析和獲取 這些依賴,確保項(xiàng)目能夠順利構(gòu)建和運(yùn)行。 依賴傳遞包括 直接依賴和間接依賴 。直接依賴是項(xiàng)目 直接引用 的庫,而間接依賴是 直接依賴所引用的其他庫 。 作用: 簡化項(xiàng)目管理 :Ma

    2024年02月02日
    瀏覽(34)
  • maven依賴管理(依賴配置、依賴傳遞、依賴沖突、依賴范圍)

    maven依賴管理(依賴配置、依賴傳遞、依賴沖突、依賴范圍)

    這篇文章會(huì)介紹在maven中的依賴配置、依賴傳遞、依賴范圍等知識(shí)點(diǎn)。 依賴配置很好理解,就是指當(dāng)前項(xiàng)目需要什么jar,就在dependencies中進(jìn)行配置 在maven管理jar的時(shí)候,沖突是肯定存在的,這里就來介紹一下在maven中對(duì)于jar的一些管理是如何進(jìn)行的,遵循什么規(guī)則。 簡單說就

    2024年02月11日
    瀏覽(27)
  • Maven 依賴傳遞和沖突、繼承和聚合

    Maven 依賴傳遞和沖突、繼承和聚合

    1.1.1 概念 ????????假如有三個(gè) Maven 項(xiàng)目 A 、 B 和 C ,其中項(xiàng)目 A? 依賴 B ,項(xiàng)目 B? 依賴 C 。那么我們可以說 A 依賴 C 。也就是說,依賴的關(guān)系為: A—B—C , 那么我們執(zhí)行項(xiàng)目 A 時(shí),會(huì)自動(dòng)把 B 和 C 都下載導(dǎo)入到 A 項(xiàng)目的 jar 包文件夾中,這就是依賴的傳遞性。 1.1.2?作

    2024年01月21日
    瀏覽(22)
  • Maven 基礎(chǔ)之依賴管理、范圍、傳遞、沖突

    Maven 基礎(chǔ)之依賴管理、范圍、傳遞、沖突

    坐標(biāo)和 mvnrepository 網(wǎng)站 在 maven 中通過『 坐標(biāo) 』概念來確定一個(gè)唯一確定的 jar 包。坐標(biāo)的組成部分有: 元素 說明 groupId 定義當(dāng)前 Maven 組織名稱 artifactId 定義實(shí)際項(xiàng)目名稱 version 定義當(dāng)前項(xiàng)目的當(dāng)前版本 [?] 注意 任意兩個(gè)不同包,它們的這三個(gè)屬性必定至少有一項(xiàng)是不同

    2024年02月12日
    瀏覽(18)
  • flink開發(fā)常見問題 —— flink-kafka 依賴版本沖突問題

    flink開發(fā)常見問題 —— flink-kafka 依賴版本沖突問題

    由于 flink / kafka 的版本不斷更新,創(chuàng)建項(xiàng)目的時(shí)候就應(yīng)當(dāng)考慮清楚這幾個(gè)依賴庫的版本問題,盡可能地與實(shí)際場景保持一致,比如服務(wù)器上部署的 kafka 是哪個(gè)版本,flink 是哪個(gè)版本,從而確定我們需要開發(fā)的是哪個(gè)版本,并且在真正的開發(fā)工作開始之前,應(yīng)當(dāng)先測試一下保證

    2024年02月07日
    瀏覽(29)
  • java.lang.IllegalStateException: Error processing condition 架包依賴版本沖突修復(fù)

    java.lang.IllegalStateException: Error processing condition 架包依賴版本沖突修復(fù)

    springboot項(xiàng)目因?yàn)樾枰有鹿δ苡谑且胄录影?,然后寫好代碼啟動(dòng)時(shí)候就報(bào)錯(cuò)了 (1)引入的新依賴包 (2)啟動(dòng)報(bào)錯(cuò) java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration.redisTemplate (3)網(wǎng)上搜解決方案第一個(gè)結(jié)果是說這是個(gè)

    2024年01月22日
    瀏覽(19)
  • Maven之高版本的 lombok 和 tomcat 7 插件沖突問題

    Maven之高版本的 lombok 和 tomcat 7 插件沖突問題

    在開發(fā)期間,當(dāng)我們使用 tomcat7-maven-plugin 來作為運(yùn)行環(huán)境運(yùn)行我們項(xiàng)目使,如果我們項(xiàng)目中使用了 1.16.20 及以上版本的 lombok 包,項(xiàng)目啟動(dòng)時(shí)會(huì)報(bào)錯(cuò): 原因在于,從 1.16.20 開始 lombok 包中有了一個(gè)叫 module-info.class 的文件,而低版本的 tomcat 不能識(shí)別這個(gè)文件,從而導(dǎo)致運(yùn)行時(shí)

    2024年02月11日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包