成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

類隔離自定義類加載器實現,你學會了嗎?

開發 前端
本文分享的方式是從類加載器方向出發,實現最終的類隔離,避免了不同模塊間不同類的沖突,其中順便也簡單帶過了jvm類加載相關的知識點,也算是一勞多得。

前言

由于微服務的快速迭代、持續集成等特性,越來越多的團隊更傾向于它。但是也體現出了一些問題,比如在基礎設施建設過程中,需要把通用功能下沉,把現有大而全的基礎設施按領域拆分,考慮需要兼容現有生產服務,會產生不同的依賴版本,有時不注意就可以引發問題。比如本文遇到的依賴包版本沖突問題,以及如何利用類隔離技術解決的分析。

類隔離是什么?

類隔離是一種通過類加載器實現加載所需類的實現方式,使得不同版本類間隔離,避免了使用沖突問題,最終的效果就是不同模塊的內容被不同的類加載器加載,滿足同一環境下同時兼容不同接口實現類。

使用場景

比如業務服務A和業務服務B均需要消息通知等,均依賴消息中間件,但所引用版本不一致,導致最終只有一個版本加載到JVM,在某一個服務調用時會出現 NoSuchMethodError或NoSuchClassError問題,這就很難排查出來,沒準會影響項目進度,最終月度的績效(“雞腿”)不保。

服務A pom.xml:

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

服務B pom.xml:

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

業務調用流程:

// 業務A調用微信服務通知
MessageUtil.sendMessage(content,peopleId,templateId,"wechat");
// 業務B調用微信服務通知
MessageUtil.sendToWechat(content,peopleId,templateId);

JVM最終加載的為 2.0.0 版本的依賴,導致業務A在調用時拋異常java.lang.NoSuchMethodError。

解決方案

大體的解決思路就是,在不改變業務代碼的前提下, 業務A調用 1.0.0 版本的消息工具類, 業務B調用2.0.0版本的消息工具類,因此需要JVM能夠利用自定義類加載器加載所需的類或關聯的類。

實現思路

  • 重寫類加載器,實現自定義類加載(java.lang.ClassLoader)
  • 重寫類加載函數

重寫 findClass(String name)

重寫 loadClass(String name)

涉及的知識點

  • JVM加載過程:加載-》鏈接-》初始化(具體后續介紹)
  • 雙親委派機制:委托父加載器查詢;如果父加載器查詢不到,則調用自身的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() {
// 業務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[]{};
}

最終結果與預期的結果不一致:

  • 預期結果:業務A的MessageServiceImpl與MessageUtil由CustomerFindClass加載
  • 實際結果:業務A的MessageServiceImpl由CustomerFindClass加載,而MessageUtil由sun.misc.AppClassLoader加載。
  • 分析:由于JVM類加載的雙親委托機制,業務A調用消息工具類時,類加載器(CustomerFindClass)會委托父類加載器(AppClassLoader)加載類,如果存在,則不再執行自身的findClass方法加載,導致結果不理想。(main 方法類默認情況下都是由 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);
}

滿足業務A的MessageServiceImpl與MessageUtil由CustomerFindClass加載

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

總結

本文分享的方式是從類加載器方向出發,實現最終的類隔離,避免了不同模塊間不同類的沖突,其中順便也簡單帶過了jvm類加載相關的知識點,也算是一勞多得。

責任編輯:武曉燕 來源: Java技術指北
相關推薦

2023-01-28 10:40:56

Java虛擬機代碼

2022-06-27 08:16:34

JSON格式序列化

2022-02-17 07:10:39

Nest自定義注解

2024-11-27 11:07:20

vue計算屬性

2023-10-06 00:01:08

UML類圖圖形

2022-06-16 07:50:35

數據結構鏈表

2023-11-06 07:25:51

Spring配置應用程序

2024-11-28 10:32:32

2023-12-26 00:55:51

資源隔離CPU

2024-07-29 10:35:44

KubernetesCSI存儲

2024-01-19 08:25:38

死鎖Java通信

2024-02-04 00:00:00

Effect數據組件

2023-07-26 13:11:21

ChatGPT平臺工具

2023-01-10 08:43:15

定義DDD架構

2022-01-20 07:31:49

架構

2024-04-09 08:41:41

JVM類加載Java

2023-08-01 12:51:18

WebGPT機器學習模型

2024-01-02 12:05:26

Java并發編程

2023-10-19 09:14:34

Java開發

2024-10-12 10:25:15

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品日韩欧美一区二区 | 国产一级毛片精品完整视频版 | 欧美白人做受xxxx视频 | 中文字幕一区二区三区乱码图片 | 久久国产精品-国产精品 | 中文字幕一区二区三区在线观看 | 伊人网在线播放 | 精品视频一区在线 | 日操操夜操操 | 亚洲性人人天天夜夜摸 | 欧美日韩亚洲一区二区 | 精品欧美一区二区三区久久久 | 精品一区二区视频 | 不卡在线视频 | 超碰97干| 亚洲一区国产 | 国产精品久久久久久久久久了 | 国产三区在线观看视频 | 午夜精品一区二区三区在线观看 | 亚洲精品18 | 性欧美xxxx | 91视频18| 国产视频综合 | 日韩成年人视频在线 | 一区二区在线免费观看 | 国产精品免费看 | 国产日韩免费视频 | 成人午夜精品 | 岛国毛片 | 亚洲国产精品一区二区第一页 | 欧美国产视频 | 色狠狠一区 | 欧美色欧美亚洲另类七区 | 国产精品明星裸体写真集 | 五月天天丁香婷婷在线中 | 久久69精品久久久久久国产越南 | 国产欧美精品一区二区色综合朱莉 | 欧美在线一区二区三区四区 | www.五月婷婷.com | 日韩激情在线 | 亚洲国产精品精华素 |