欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java通過(guò)自定義類加載器實(shí)現(xiàn)類隔離

 更新時(shí)間:2022年08月08日 08:24:47   作者:指北君  
類隔離是一種通過(guò)類加載器實(shí)現(xiàn)加載所需類的實(shí)現(xiàn)方式,使得不同版本類間隔離,避免了使用沖突問(wèn)題。本文將通過(guò)自定義的類加載器實(shí)現(xiàn)類隔離,感興趣的可以了解一下

前言

由于微服務(wù)的快速迭代、持續(xù)集成等特性,越來(lái)越多的團(tuán)隊(duì)更傾向于它。但是也體現(xiàn)出了一些問(wèn)題,比如在基礎(chǔ)設(shè)施建設(shè)過(guò)程中,需要把通用功能下沉,把現(xiàn)有大而全的基礎(chǔ)設(shè)施按領(lǐng)域拆分,考慮需要兼容現(xiàn)有生產(chǎn)服務(wù),會(huì)產(chǎn)生不同的依賴版本,有時(shí)不注意就可以引發(fā)問(wèn)題。比如本文遇到的依賴包版本沖突問(wèn)題,以及如何利用類隔離技術(shù)解決的分析。

類隔離是什么

類隔離是一種通過(guò)類加載器實(shí)現(xiàn)加載所需類的實(shí)現(xiàn)方式,使得不同版本類間隔離,避免了使用沖突問(wèn)題,最終的效果就是不同模塊的內(nèi)容被不同的類加載器加載,滿足同一環(huán)境下同時(shí)兼容不同接口實(shí)現(xiàn)類。

使用場(chǎng)景

比如業(yè)務(wù)服務(wù)A和業(yè)務(wù)服務(wù)B均需要消息通知等,均依賴消息中間件,但所引用版本不一致,導(dǎo)致最終只有一個(gè)版本加載到JVM,在某一個(gè)服務(wù)調(diào)用時(shí)會(huì)出現(xiàn) NoSuchMethodError或NoSuchClassError問(wèn)題,這就很難排查出來(lái),沒(méi)準(zhǔn)會(huì)影響項(xiàng)目進(jìn)度,最終月度的績(jī)效(“雞腿”)不保。

服務(wù)A pom.xml:

??<!--?common-message-->
????????<dependency>
????????????<groupId>com.lgy</groupId>
????????????<artifactId>spring-common-message</artifactId>
????????????<version>1.0.0<version>
????????</dependency>

服務(wù)B pom.xml:

??<!--?common-message-->
????????<dependency>
????????????<groupId>com.lgy</groupId>
????????????<artifactId>spring-common-message</artifactId>
????????????<version>2.0.0<version>
????????</dependency>

業(yè)務(wù)調(diào)用流程:

?//?業(yè)務(wù)A調(diào)用微信服務(wù)通知
?MessageUtil.sendMessage(content,peopleId,templateId,"wechat");
?//?業(yè)務(wù)B調(diào)用微信服務(wù)通知
?MessageUtil.sendToWechat(content,peopleId,templateId);

JVM最終加載的為 2.0.0 版本的依賴,導(dǎo)致業(yè)務(wù)A在調(diào)用時(shí)拋異常java.lang.NoSuchMethodError。

解決方案

大體的解決思路就是,在不改變業(yè)務(wù)代碼的前提下, 業(yè)務(wù)A調(diào)用 1.0.0 版本的消息工具類, 業(yè)務(wù)B調(diào)用2.0.0版本的消息工具類,因此需要JVM能夠利用自定義類加載器加載所需的類或關(guān)聯(lián)的類。

實(shí)現(xiàn)思路

重寫類加載器,實(shí)現(xiàn)自定義類加載(java.lang.ClassLoader)

重寫類加載函數(shù)

  • 重寫 findClass(String name)
  • 重寫 loadClass(String name)

涉及的知識(shí)點(diǎn)

  • JVM加載過(guò)程:加載-》鏈接-》初始化(具體后續(xù)介紹)
  • 雙親委派機(jī)制:委托父加載器查詢;如果父加載器查詢不到,則調(diào)用自身的findClass加載

重寫findClass

?import?java.io.*;
?import?java.util.HashMap;
?import?java.util.Map;

?public?class?CustomerFindClass?extends?ClassLoader?{
??private?Map<String,?String>?classPathMap?=?new?HashMap<>();
??public?CustomerFindClass()?{
???//?業(yè)務(wù)A的自定義類加載器
???classPathMap.put("com.lgy.businessA.service.impl.MessageServiceImpl",?"E:/dataway-demo/example/target/classes/com/lgy/businessA/service/impl/MessageServiceImpl.class");
???classPathMap.put("com.lgy.v1.message.util.MessageUtil",?"E:/dataway-demo/example/target/classes/com/lgy/v1/message/util/MessageUtil.class");
??}
??
??/**
??*?findClass方式加載類
??*/
??@Override
??protected?Class<?>?findClass(String?name)?throws?ClassNotFoundException?{
???String?classPath?=?classPathMap.get(name);
???File?file?=?new?File(classPath);
???if?(!file.exists())?{
????throw?new?ClassNotFoundException();
???}
???byte[]?bytes?=?getClassData(file);
???if?(null?==?bytes?||?0?==?bytes.length)?{
????throw?new?ClassNotFoundException();
???}
???return?defineClass(bytes,?0,?bytes.length);
??}
??
??private?byte[]?getClassData(File?file)?{
???try?(InputStream?ins?=?new?FileInputStream(file);?
?????ByteArrayOutputStream?baos?=?new?ByteArrayOutputStream())?{
????byte[]?buffer?=?new?byte[4096];
????int?bytesNumRead?=?0;
????while?((bytesNumRead?=?ins.read(buffer))?!=?-1)?{
?????baos.write(buffer,?0,?bytesNumRead);
????}
????return?baos.toByteArray();
???}?catch?(FileNotFoundException?e)?{
????e.printStackTrace();
???}?catch?(IOException?e)?{
????e.printStackTrace();
???}
???return?new?byte[]{};
??}

最終結(jié)果與預(yù)期的結(jié)果不一致

  • 預(yù)期結(jié)果:業(yè)務(wù)A的MessageServiceImpl與MessageUtil由CustomerFindClass加載
  • 實(shí)際結(jié)果:業(yè)務(wù)A的MessageServiceImpl由CustomerFindClass加載,而MessageUtil由sun.misc.AppClassLoader加載。
  • 分析:由于JVM類加載的雙親委托機(jī)制,業(yè)務(wù)A調(diào)用消息工具類時(shí),類加載器(CustomerFindClass)會(huì)委托父類加載器(AppClassLoader)加載類,如果存在,則不再執(zhí)行自身的findClass方法加載,導(dǎo)致結(jié)果不理想。(main 方法類默認(rèn)情況下都是由 JDK 自帶的 AppClassLoader 加載的)。

重寫loadClass

?private?ClassLoader?classLoader;
?
?/**
?*?重新loadClass方法
?*/
?@Override
????protected?Class<?>?loadClass(String?name,?boolean?resolve)?throws?ClassNotFoundException?{
????????Class?result?=?null;
????????try?{
????????????//這里要使用?JDK?的類加載器加載?java.lang?包里面的類
????????????result?=?classLoader.loadClass(name);
????????}?catch?(Exception?e)?{
????????????//?ignore?error
????????}
????????if?(null?!=?result)?{
????????????return?result;
????????}
????????String?classPath?=?classPathMap.get(name);
????????File?file?=?new?File(classPath);
????????if?(!file.exists())?{
????????????throw?new?ClassNotFoundException();
????????}
????????byte[]?bytes?=?getClassData(file);
????????if?(null?==?bytes?||?0?==?bytes.length)?{
????????????throw?new?ClassNotFoundException();
????????}
????????return?defineClass(bytes,?0,?bytes.length);
????}

滿足業(yè)務(wù)A的MessageServiceImpl與MessageUtil由CustomerFindClass加載

注意:這種方式破壞了雙親委托機(jī)制,但由于重寫了loadClass方法,所有類均會(huì)有CustomerFindClass加載器加載,需要過(guò)濾出不需要隔離的類,如java.lang包下的類,需要由ExtClassLoader 來(lái)加載。

總結(jié)

本文分享的方式是從類加載器方向出發(fā),實(shí)現(xiàn)最終的類隔離,避免了不同模塊間不同類的沖突,其中順便也簡(jiǎn)單帶過(guò)了jvm類加載相關(guān)的知識(shí)點(diǎn),也算是一勞多得,后續(xù)會(huì)結(jié)合實(shí)際使用場(chǎng)景進(jìn)一步分析。

以上就是Java通過(guò)自定義類加載器實(shí)現(xiàn)類隔離的詳細(xì)內(nèi)容,更多關(guān)于Java類隔離的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot注入Bean的四種方式總結(jié)

    SpringBoot注入Bean的四種方式總結(jié)

    這篇文章主要給大家總結(jié)SpringBoot注入Bean的四種方式,啟動(dòng)類注入Bean,啟動(dòng)類掃描@ComponentScan,啟動(dòng)類@EnableConfigurationProperties以及啟動(dòng)類@Import這四種方式,文章通過(guò)代碼示例講解非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • java:找不到符號(hào)報(bào)錯(cuò)的排錯(cuò)方案舉例

    java:找不到符號(hào)報(bào)錯(cuò)的排錯(cuò)方案舉例

    當(dāng)你使用一個(gè)未定義或未導(dǎo)入的類時(shí),編譯器會(huì)報(bào)錯(cuò),下面這篇文章主要給大家介紹了關(guān)于java:找不到符號(hào)報(bào)錯(cuò)的排錯(cuò)方案,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • 關(guān)于Java中代碼塊的執(zhí)行順序

    關(guān)于Java中代碼塊的執(zhí)行順序

    這篇文章主要介紹了關(guān)于Java中代碼塊的執(zhí)行順序,構(gòu)造代碼塊是給所有對(duì)象進(jìn)行統(tǒng)一初始化,而構(gòu)造函數(shù)是給對(duì)應(yīng)的對(duì)象初始化,因?yàn)闃?gòu)造函數(shù)是可以多個(gè)的,運(yùn)行哪個(gè)構(gòu)造函數(shù)就會(huì)建立什么樣的對(duì)象,但無(wú)論建立哪個(gè)對(duì)象,都會(huì)先執(zhí)行相同的構(gòu)造代碼塊,需要的朋友可以參考下
    2023-08-08
  • Servlet Filter過(guò)濾器執(zhí)行順序

    Servlet Filter過(guò)濾器執(zhí)行順序

    這篇文章主要介紹了Servlet Filter過(guò)濾器執(zhí)行順序的相關(guān)資料,幫助大家更好的理解為什么要用過(guò)濾器,感興趣的朋友可以了解下
    2020-12-12
  • 詳解Java實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)之并查集

    詳解Java實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)之并查集

    并查集這種數(shù)據(jù)結(jié)構(gòu),可能出現(xiàn)的頻率不是那么高,但是還會(huì)經(jīng)常性的見(jiàn)到,其理解學(xué)習(xí)起來(lái)非常容易,通過(guò)本文,一定能夠輕輕松松搞定并查集
    2021-06-06
  • java實(shí)現(xiàn)建造者模式(Builder Pattern)

    java實(shí)現(xiàn)建造者模式(Builder Pattern)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)建造者模式Builder Pattern,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • Java遞歸求和1+2+3+...+n實(shí)例詳解

    Java遞歸求和1+2+3+...+n實(shí)例詳解

    在本篇文章里小編給大家?guī)?lái)了關(guān)于Java遞歸求和1+2+3+...+n實(shí)例內(nèi)容,需要的朋友們可以學(xué)習(xí)參考下。
    2020-01-01
  • Java中volatile防止指令重排

    Java中volatile防止指令重排

    volatile可以防止指令重排,在多線程環(huán)境下有時(shí)候我們需要使用volatile來(lái)防止指令重排,來(lái)保證代碼運(yùn)行后數(shù)據(jù)的準(zhǔn)確性,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Java 添加文本框到PPT幻燈片過(guò)程解析

    Java 添加文本框到PPT幻燈片過(guò)程解析

    這篇文章主要介紹了Java 添加文本框到PPT幻燈片過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • 詳解Spring DeferredResult異步操作使用場(chǎng)景

    詳解Spring DeferredResult異步操作使用場(chǎng)景

    本文主要介紹了Spring DeferredResult異步操作使用場(chǎng)景,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10

最新評(píng)論