0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

類隔離的使用場(chǎng)景

科技綠洲 ? 來(lái)源:Java技術(shù)指北 ? 作者:Java技術(shù)指北 ? 2023-10-08 15:20 ? 次閱讀

前言

由于微服務(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)一步分析。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8447

    瀏覽量

    150724
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4283

    瀏覽量

    62325
  • 微服務(wù)
    +關(guān)注

    關(guān)注

    0

    文章

    131

    瀏覽量

    7322
  • 類加載器
    +關(guān)注

    關(guān)注

    0

    文章

    6

    瀏覽量

    922
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    AG32VF-MIPI應(yīng)用場(chǎng)景

    MIPI接口技術(shù)在圖像和視頻傳輸中的應(yīng)用越來(lái)越廣泛,應(yīng)用場(chǎng)景也在不斷拓展,而不僅限于移動(dòng)設(shè)備。MIPI接口在物聯(lián)網(wǎng)、智能家居、智能監(jiān)控、智能電視、智能汽車等領(lǐng)域也得到廣泛應(yīng)用。 MIPI還可
    發(fā)表于 01-22 08:56

    太陽(yáng)膜測(cè)試儀的技術(shù)原理和應(yīng)用場(chǎng)景

    太陽(yáng)膜測(cè)試儀的技術(shù)原理和應(yīng)用場(chǎng)景可以詳細(xì)闡述如下:技術(shù)原理太陽(yáng)膜測(cè)試儀的技術(shù)原理主要基于光學(xué)測(cè)量和物理定律。具體來(lái)說(shuō),它通過(guò)模擬太陽(yáng)光中的各種波長(zhǎng)(主要是紫外線、可見(jiàn)光和紅外線)的輻射,來(lái)檢測(cè)太陽(yáng)膜
    發(fā)表于 09-29 14:18

    可展示三種RS485應(yīng)用場(chǎng)景的半雙工參考設(shè)計(jì)包括BOM及層圖

    描述 RS485(隔離式、非隔離式)是適用于電網(wǎng)基礎(chǔ)設(shè)施空間的常用接口,也是新設(shè)計(jì)的設(shè)備上最重要的選項(xiàng)之一。TIDA-00308 允許客戶針對(duì)三種不同應(yīng)用場(chǎng)景通過(guò) TI RS485 器件以及該
    發(fā)表于 09-21 09:15

    MOS管的應(yīng)用場(chǎng)景

    mos管的應(yīng)用場(chǎng)景,你了解么?低壓MOS管可稱為金屬氧化物半導(dǎo)體場(chǎng)效應(yīng)管,因?yàn)榈蛪篗OS管具有良好的開(kāi)關(guān)特性,廣泛應(yīng)用在電子開(kāi)關(guān)的電路中。如開(kāi)關(guān)電源,電動(dòng)馬達(dá)、照明調(diào)光等!下面銀聯(lián)寶科技就跟大家一起
    發(fā)表于 11-14 09:24

    this的使用場(chǎng)景及與C,Java中的this的區(qū)別

    【JS】this有哪些使用場(chǎng)景?跟C,Java中的this有什么區(qū)別?如何改變this的值?
    發(fā)表于 03-11 10:17

    CP-OFMD調(diào)制波形應(yīng)用場(chǎng)景

    圖1、5G的應(yīng)用場(chǎng)景5G使用5G多載波波形來(lái)為智能手機(jī),辦公室,工廠自動(dòng)化,智能電網(wǎng),智慧城市,物聯(lián)網(wǎng),M2M,M2X等多種設(shè)備提供應(yīng)用平臺(tái)。5G新無(wú)線電(5G NR)根據(jù)應(yīng)用場(chǎng)景可分為三大服務(wù)
    發(fā)表于 06-18 06:51

    =>的使用場(chǎng)景有哪些

    使用場(chǎng)景
    發(fā)表于 10-27 13:25

    運(yùn)放電路有哪些應(yīng)用場(chǎng)景?

    運(yùn)放電路的七大應(yīng)用場(chǎng)景
    發(fā)表于 03-11 07:49

    藍(lán)牙低功耗常見(jiàn)的應(yīng)用場(chǎng)景及架構(gòu)

    淺談藍(lán)牙低功耗(BLE)的幾種常見(jiàn)的應(yīng)用場(chǎng)景及架構(gòu)
    發(fā)表于 06-15 09:51

    FPGA的應(yīng)用場(chǎng)景

    目錄文章目錄目錄FPGAFPGA 的應(yīng)用場(chǎng)景FPGA 的技術(shù)難點(diǎn)FPGA 的工作原理FPGA 的體系結(jié)構(gòu)FPGA 的開(kāi)發(fā)FPGA 的使用FPGA 的優(yōu)缺點(diǎn)參考文檔FPGAFPGA(Field
    發(fā)表于 07-28 08:43

    ARM的技術(shù)特征是什么?應(yīng)用場(chǎng)景有哪些?

    ARM的技術(shù)特征是什么?應(yīng)用場(chǎng)景有哪些?
    發(fā)表于 11-05 07:32

    MS9331的應(yīng)用場(chǎng)景是什么?

    MS9331的應(yīng)用場(chǎng)景是什么?
    發(fā)表于 02-11 06:41

    RK3308的特點(diǎn)及應(yīng)用場(chǎng)景是什么?

    RK3308的特點(diǎn)及應(yīng)用場(chǎng)景是什么?
    發(fā)表于 03-09 08:04

    labview 和 wincc 的區(qū)別 使用場(chǎng)景

    labview 和 wincc 的區(qū)別 使用場(chǎng)景 都是上位機(jī)軟件,都可以做監(jiān)控軟件 wincc的名氣也比較大 對(duì)比的資料較少 寫這些文章的人,從自己的從事的行業(yè)出發(fā),帶有自己的思維 使用的場(chǎng)景 肯定
    發(fā)表于 10-27 18:01

    榮湃隔離驅(qū)動(dòng)器的應(yīng)用場(chǎng)景有哪些?

    隔離驅(qū)動(dòng)器的一大應(yīng)用場(chǎng)景是取代數(shù)字隔離器+MOS驅(qū)動(dòng)器的分立設(shè)計(jì),高絕緣耐壓要求的半橋驅(qū)動(dòng)應(yīng)用中,部分系統(tǒng)采用了雙通道數(shù)字隔離器配合高低邊MOS驅(qū)動(dòng)器的設(shè)計(jì)。
    的頭像 發(fā)表于 04-01 15:42 ?2121次閱讀