最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解決版本不兼容Jar包沖突問題

 更新時(shí)間:2023年10月03日 10:53:33   作者:IT楓斗者  
在和三方對(duì)接的過(guò)程中,我們可能會(huì)不斷引入一些三方j(luò)ar包,但這個(gè)時(shí)候就有可能出現(xiàn)一個(gè)項(xiàng)目需要依賴兩個(gè)版本不同且功能不兼容的jar包,本文主要介紹了解決版本不兼容Jar包沖突問題,感興趣的可以了解一下

引言

“老婆”和“媽媽”同時(shí)掉進(jìn)水里,先救誰(shuí)?

常言道:編碼五分鐘,解沖突兩小時(shí)。作為Java開發(fā)來(lái)說(shuō),第一眼見到ClassNotFoundException、

NoSuchMethodException這些異常來(lái)說(shuō),第一反應(yīng)就是排包。經(jīng)過(guò)一通常規(guī)和非常規(guī)操作以后,往往會(huì)找到同一個(gè)Jar包引入了多個(gè)不同的版本,這時(shí)候一般排除掉低版本、保留高版本就可以了,這是因?yàn)橐话鉐ar包都是向下兼容的。但是,如果出現(xiàn)版本不兼容的情況的時(shí)候,就會(huì)陷入“老婆和媽同時(shí)掉進(jìn)水里,先救誰(shuí)”的兩難境地,如果恰恰這種不兼容發(fā)生在中間件依賴和業(yè)務(wù)自身依賴之間,那就更難了。 如下圖所示,Project表示我們的項(xiàng)目,Dependency A表示我們的業(yè)務(wù)依賴,Dependency B表示中間件依賴,如果業(yè)務(wù)依賴和中間件依賴都依賴同一個(gè)Jar包C,但是版本卻不一樣,分別為0.1版本和0.2版本,而且最不巧的是這兩個(gè)版本還存在沖突,有些老的功能只在0.1低版本中存在,有些新功能只在0.2高版本中存在,真是“老婆和媽同時(shí)掉進(jìn)水里,先救誰(shuí)都不行”。

俗話說(shuō):沒有遇到過(guò)Jar包沖突的開發(fā),一定是個(gè)假Java開發(fā);沒有解決過(guò)Jar包沖突的開發(fā),不是一個(gè)合格的Java開發(fā)。在最近的項(xiàng)目里,我們需要使用Guava的高版本Jar包,但是發(fā)現(xiàn)中間件依賴的是低版本且與高版本不兼容的Jar包,面對(duì)這種兩難,我們肯定是“老婆”和“媽媽”都要救,于是我們開始尋求解決方案。

不兼容依賴沖突解決方案

“老婆”和“媽媽”都要救,怎么救?

首先,我們想到的是,能不能把需要用到的Guava高版本的代碼拷出來(lái)直接放到我們的工程中去,但是這樣做會(huì)帶來(lái)幾個(gè)問題:

  • 1)Guava作為一個(gè)功能豐富的基礎(chǔ)庫(kù),某一部分的代碼往往與其他很多代碼都存在依賴關(guān)系,這會(huì)造成牽一發(fā)而動(dòng)全身,工作量會(huì)比預(yù)想的要大很多;
  • 2)拷貝出來(lái)的代碼只能自己手動(dòng)維護(hù),如果官方修復(fù)了問題或者重構(gòu)了代碼或者增加了功能,我們想要升級(jí)的話,那么只能重頭再來(lái)一遍。于是,我們只能另外想其他的方案,這個(gè)只能作為最后的兜底方案。

然后,我們?cè)谙耄粋€(gè)Java類被加載到JVM虛擬機(jī)里區(qū)別于另一個(gè)Class,其一是它們倆全路徑不一樣,是風(fēng)馬牛不相及的兩個(gè)不同的類,但卻是被不同的類加載器加載的,在JVM虛擬機(jī)里它們?nèi)匀槐徽J(rèn)為是兩個(gè)不同的Class。所以,我們就在想從類加載器上來(lái)尋求解決方案。在阿里巴巴內(nèi)部,有一個(gè)Pandora的組件,正如其名就像一個(gè)魔盒,它會(huì)把中間件的依賴都裝到Pandora里(內(nèi)部叫做Sar包),這樣的話,就能避免在中間件和業(yè)務(wù)代碼直接出現(xiàn)“老婆和媽同時(shí)掉進(jìn)水里,先救誰(shuí)”的兩難境地。

同樣,在類似的場(chǎng)景比如應(yīng)用合并部署也能發(fā)揮威力。但是Pandora只在阿里內(nèi)部使用并未開源。在螞蟻金服,也有一個(gè)這樣的組件,并且開源了,叫做SOFAArk(官方網(wǎng)址,感興趣的可以去官網(wǎng)了解SOFAArk的原理和使用),我們感覺已經(jīng)找到了那個(gè)Mr.Right,于是我們開始研究SOFAArk如何使用。和Pandora一樣,SOFAArk也是通過(guò)使用不同的 ClassLoader 加載不同版本的三方依賴,進(jìn)而隔離類,徹底解決包沖突的問題,這就要求我們需要將相關(guān)的依賴打包成Ark Plugin(參見SOFAArk官方文檔)。

對(duì)于公司來(lái)說(shuō),這樣的方案收益是比較大的,打包成Ark Plugin后整個(gè)公司都能夠共享,業(yè)務(wù)方都能受益,但是對(duì)于我們一個(gè)項(xiàng)目來(lái)說(shuō),采用這樣的方案無(wú)疑過(guò)重了。于是,我們與中間件同學(xué)聯(lián)系,詢問是否有計(jì)劃引入類似的隔離組件解決中間件和業(yè)務(wù)代碼之間的依賴沖突問題,得到的答復(fù)是公司目前包沖突并不是一個(gè)強(qiáng)烈的痛點(diǎn),暫時(shí)沒有計(jì)劃引入。于是,我們只能暫且擱置SOFAArk,繼續(xù)尋找新的解決方案。

接著,我們?cè)谙爰热籔andora/SOFAArk采用類加載隔離了同一路徑的類,那么如果我們把沖突的兩個(gè)版本庫(kù)的groupId變得不一樣,那么即使同名的類全路徑也是不一樣的,這樣在JVM里面必然是不同的Class。如果把Pandora/SOFAArk的隔離方式稱之為邏輯隔離的話,這種就相當(dāng)于物理隔離了。要實(shí)現(xiàn)這一點(diǎn),借助IDE的重構(gòu)功能或者全局替換的功能就能比較容易的實(shí)現(xiàn)這一點(diǎn)。 正在我們準(zhǔn)備擼起袖子動(dòng)手干的時(shí)候,我們不禁在想,這樣的痛點(diǎn)應(yīng)該早就有人遇到,尤其像Guava、Commons這類的基礎(chǔ)類庫(kù),沖突在所難免,前人應(yīng)該已經(jīng)找到了優(yōu)雅的撓癢姿勢(shì)。于是,我們就去搜索相關(guān)的文章,果不其然,maven-shade-plugin正是那優(yōu)雅的撓癢姿勢(shì),這個(gè)Maven插件的原理正是將類的包路徑進(jìn)行重新映射,達(dá)到隔離不兼容Jar包的目的。

maven-shade-plugin解決依賴沖突*

最后如何來(lái)配置和使用maven-shade-plugin將Guava映射成我們自己定制的Jar包,實(shí)現(xiàn)與中間件Guava的隔離。整個(gè)的過(guò)程還是比較清晰明了的,主要是創(chuàng)建一個(gè)Maven工程,引入依賴,配置我們要發(fā)布的倉(cāng)庫(kù)地址,引入編譯打包插件和maven-shade-plugin插件,配置映射規(guī)則(標(biāo)簽之間部分),然后編譯打包發(fā)布到Maven倉(cāng)庫(kù)。pom.xml的配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.shaded.example</groupId>
    <artifactId>guava-wrapper</artifactId>
    <version>${guava.wrapper.version}</version>
    <name>guava-wrapper</name>
    <url>https://example.com/guava-wrapper</url>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <!- 版本與 guava 版本基本保持一致 ->
        <guava.wrapper.version>27.1-jre</guava.wrapper.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>27.1-jre</version>
        </dependency>  
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.3.2</version>
                <executions>
                    <execution>
                        <id>default-jar</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                        <phase>package</phase>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>2.4</version>
                <executions>
                    <execution>
                        <id>default-sources</id>
                        <goals>
                            <goal>jar-no-fork</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.4.1</version>
                <configuration>
                    <createDependencyReducedPom>false</createDependencyReducedPom>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                                          <!-- 重命名規(guī)則配置 -->
                            <relocations>
                                <relocation>
                                                      <!-- 源包路徑 -->
                                    <pattern>com.google.guava</pattern>
                                                      <!-- 目標(biāo)包路徑 -->
                                    <shadedPattern>com.google.guava.wrapper</shadedPattern>
                                </relocation>
                                <relocation>
                                    <pattern>com.google.common</pattern>
                                    <shadedPattern>com.google.common.wrapper</shadedPattern>
                                </relocation>
                                <relocation>
                                    <pattern>com.google.thirdparty</pattern>
                                    <shadedPattern>com.google.wrapper.thirdparty</shadedPattern>
                                </relocation>
                            </relocations>
                            <transformers>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <distributionManagement>
          <!- Maven倉(cāng)庫(kù)配置,略 ->
    </distributionManagement>
</project>

項(xiàng)目引入這個(gè)新打包的guava-wrapper后,import選擇從這個(gè)包導(dǎo)入我們需要的相關(guān)類即可。如下:

<dependency>
  <groupId>com.vivo.internet</groupId>
  <artifactId>guava-wrapper</artifactId>
  <version>27.1-jre</version>
</dependency>

結(jié)語(yǔ)

為了在同一個(gè)項(xiàng)目中使用多個(gè)版本不兼容的Jar包,我們首先想到手動(dòng)自行維護(hù)代碼,但是工作量和維護(hù)成本很高,接著我們想到通過(guò)類加載器隔離(開源方案SOFAArk),但是需要將相關(guān)依賴都打包成Ark Plugin,解決方案無(wú)疑有點(diǎn)過(guò)重了,最后通過(guò)maven-shade-plugin插件重命名并打包,優(yōu)雅地解決了項(xiàng)目中不兼容多個(gè)版本Jar包的沖突問題。從問題出來(lái),我們一步一步探尋問題的解決方案,最終的maven-shade-plugin插件方案雖然看似與手動(dòng)自行維護(hù)代碼本質(zhì)一致,看似回到了原點(diǎn),但其實(shí)最終的方案優(yōu)雅性遠(yuǎn)比最開始高得多,正如人生的道路那樣,螺旋式上升,曲線式前進(jìn)。

如果遇到類似需要支持版本不兼容Jar包共存的場(chǎng)景,可以考慮使用maven-shade-plugin插件,這種方法比較輕量級(jí),可用于項(xiàng)目中存在個(gè)別不兼容Jar包沖突的場(chǎng)景,簡(jiǎn)單有效,成本也很低。但是,如果Jar包沖突現(xiàn)象比較普遍,已成為明顯或者普遍的痛點(diǎn),還是建議考慮文中提到的類似Pandora、SOFAArk等類加載器隔離的方案。

到此這篇關(guān)于解決版本不兼容Jar包沖突問題的文章就介紹到這了,更多相關(guān)版本不兼容Jar包沖突內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java通過(guò)snmp協(xié)議獲取物理設(shè)備信息

    java通過(guò)snmp協(xié)議獲取物理設(shè)備信息

    這篇文章主要介紹了java通過(guò)snmp協(xié)議獲取物理設(shè)備信息,snmp中文含義是簡(jiǎn)單網(wǎng)絡(luò)管理協(xié)議,可用完成對(duì)計(jì)算機(jī)、路由器和其他網(wǎng)絡(luò)設(shè)備的遠(yuǎn)程管理和監(jiān)視,本文我們是通過(guò)java程序來(lái)獲取,需要的朋友可以參考下
    2023-07-07
  • Java8加java10等于Java18的版本查看及特性詳解

    Java8加java10等于Java18的版本查看及特性詳解

    這篇文章主要為大家介紹了Java?8加java10等于Java18的各個(gè)版本要點(diǎn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 詳解Java關(guān)于JDK中時(shí)間日期的API

    詳解Java關(guān)于JDK中時(shí)間日期的API

    這篇文章主要介紹了詳解Java關(guān)于JDK中時(shí)間日期的API,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • SpringBoot請(qǐng)求體缺失異常原因分析與處理方案

    SpringBoot請(qǐng)求體缺失異常原因分析與處理方案

    這篇文章主要介紹了SpringBoot請(qǐng)求體缺失異常原因分析與處理方案,該異常是因?yàn)閁serController的edit方法缺失了預(yù)期的UserUpdatePwdDTO請(qǐng)求體,產(chǎn)生原因主要由前端未發(fā)送請(qǐng)求體、Content-Type設(shè)置錯(cuò)誤或后端缺少@RequestBody注解導(dǎo)致,需要的朋友可以參考下
    2025-10-10
  • SpringBoot使用開發(fā)環(huán)境application.properties問題

    SpringBoot使用開發(fā)環(huán)境application.properties問題

    這篇文章主要介紹了SpringBoot使用開發(fā)環(huán)境application.properties問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Java中synchronized正確使用方法解析

    Java中synchronized正確使用方法解析

    這篇文章主要介紹了Java中syncronized正確使用方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • JavaSwing GridLayout 網(wǎng)格布局的實(shí)現(xiàn)代碼

    JavaSwing GridLayout 網(wǎng)格布局的實(shí)現(xiàn)代碼

    這篇文章主要介紹了JavaSwing GridLayout 網(wǎng)格布局的實(shí)現(xiàn)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • 詳解servlet配置load-on-startup的作用

    詳解servlet配置load-on-startup的作用

    本文對(duì)load-on-startup的相關(guān)內(nèi)容作了詳細(xì)介紹,然后通過(guò)具體實(shí)例向大家展示了其作用,希望可以給大家一個(gè)參考。
    2017-09-09
  • Kotlin基礎(chǔ)教程之Run,標(biāo)簽Label,函數(shù)Function-Type

    Kotlin基礎(chǔ)教程之Run,標(biāo)簽Label,函數(shù)Function-Type

    這篇文章主要介紹了Kotlin基礎(chǔ)教程之Run,標(biāo)簽Label,函數(shù)Function-Type的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • Java函數(shù)式編程(三):列表的轉(zhuǎn)化

    Java函數(shù)式編程(三):列表的轉(zhuǎn)化

    這篇文章主要介紹了Java函數(shù)式編程(二):列表的轉(zhuǎn)化,lambda表達(dá)式不僅能幫助我們遍歷集合,并且可以進(jìn)行集合的轉(zhuǎn)化,需要的朋友可以參考下
    2014-09-09

最新評(píng)論

邢台市| 三亚市| 永和县| 静宁县| 重庆市| 武川县| 鹤山市| 邯郸县| 衡南县| 兴文县| 长治市| 滨海县| 徐汇区| 施秉县| 甘肃省| 米脂县| 昌都县| 滦南县| 福贡县| 大姚县| 贵州省| 塘沽区| 塔城市| 凤山县| 宁德市| 武川县| 古交市| 太仆寺旗| 于都县| 恩施市| 察哈| 商河县| 阿荣旗| 博野县| 韶山市| 巴林左旗| 延庆县| 睢宁县| 刚察县| 油尖旺区| 长春市|