范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Java类隔离应用多Jar包支持

  案例需求
  现在有一个"统一管理平台",用于统一对接三方平台,屏蔽相同业务三方平台的差异性,减少内部平台对接的成本。正常情况下三方平台提供的 SDK 是通用的(和内部平台无关),但是有一些比较特殊的三方(假如是三方平台 A),他提供的 SDK 是给内部平台定制的。
  这时就需要根据访问"统一管理平台"的内部平台类型,动态的选择使用哪个三方平台 A 的 Jar 包,比如内部平台 A 访问三方平台 A,就需要调用为 A 定制的 Jar 包。
  这个需求需要解决如下两个问题:如何在同一套环境中同时存在多个同平台不同版本的 Jar 包(这些 Jar 包中的类大部分相同,只有预设的配置参数不同)?如何根据内部平台类型,选择需要调用的 Jar 包?类加载
  我们知道如果想要使用一个类,那么这个类必须通过类加载器将其加载到内存中,在未自定义类加载器之前,JVM 是通过 ApplicationClassLoader、ExtensionClassLoader、BootstrapClassLoader 这三个类加载器基于双亲委派机制完成类的加载。这三个类加载器具有各自加载类的范围如下图所示:
  类隔离机制
  要想解决上面的第一个问题(多个同平台不同版本 Jar 包同时存在),就必须先了解一下类隔离机制。
  类隔离机制原理其实很简单,就是让每个三方平台 A 定制的 Jar 使用单独的类加载器来加载,这样每个 Jar 包之间相互隔离不会相互影响。这是因为即使同一个类使用不同的类加载器加载,对于 JVM 也是两个不同的类(虽然类的结构相同),在 JVM 中类的唯一标识是:类加载器 + 类名。
  要保证不同 Jar 包内的类隔离,还需要做到一点,就是 Jar 包中的某个类使用某个类加载器加载,那么其引用的类均使用该类加载器加载,这就是类加载传导规则 。
  代码实现
  使用 IDEA 创建三个 Maven 项目:third-party-A-for-A:三方平台 A 为内部平台 A 定制的 Jarthird-party-A-for-B:三方平台 A 为内部平台 B 定制的 Jarunified-management-platform:统一管理平台,用于通过访问的内部平台类型,动态选择调用三方平台 A 的 Jar
  项目:third-party-A-for-A
  pom.xml<?xml version="1.0" encoding="UTF-8"?>      4.0.0      com.thirdparty.A     third-party-A-for-A     1.0-SNAPSHOT     三方平台 A 为内部平台 A 定制 Jar 包               17         17                                 cn.hutool             hutool-all             5.8.5               
  定义两个类:TPAAccessService:用于提供给调用方的统一调用入口类SendRequestProvider:Jar 内部使用的类,用于提供向三方平台 A 发送请求的类,另外一个作用是验证"类加载传导规则"
  TPAAccessService.java/**  * TPA(Third Party A:三方平台 A 简称)  * 该类为调用方提供统一的方法调用入口,调用三方 A 只需要使用该类即可  *  * @since 2023/1/14 9:45  */ public class TPAAccessService {      public static void send() {         SendRequestProvider.send();     } }
  SendRequestProvider.javaimport cn.hutool.core.lang.Console;  /**  * 该类提供向三方平台 A 发送请求的方法  *  * @since 2023/1/14 9:48  */ class SendRequestProvider {      /**      * 三方平台 A 为内部平台 A 预设的密钥,用于加解密      */     private static final String SECRET_KEY = "AAAAAAAAAAA";       /**      * 发送请求到三方平台 A      */     public static void send() {         Console.log("[A -> TPA] 密钥:{}   ClassLoader:{}", SECRET_KEY, SendRequestProvider.class.getClassLoader());     } }
  项目:third-party-A-for-B
  与 third-party-A-for-A  基本相同,除了 SendRequestProvider.java  中的密钥不同,如下所示:class SendRequestProvider {      /**      * 三方平台 A 为内部平台 B 预设的密钥,用于加解密      */     private static final String SECRET_KEY = "BBBBBBBBBBB";       /**      * 发送请求到三方平台 A      */     public static void send() {         Console.log("[B -> TPA] 密钥:{}   ClassLoader:{}", SECRET_KEY, SendRequestProvider.class.getClassLoader());     } }
  项目:
  unified-management-platform
  pom.xml<?xml version="1.0" encoding="UTF-8"?>      4.0.0      com.ump     unified-management-platform     1.0-SNAPSHOT     统一管理平台               17         17                                 org.projectlombok             lombok             1.18.24                               cn.hutool             hutool-all             5.8.5               
  定义两个类:TPAClassLoader:自定义类加载器,用于加载为内部平台定制的相应 Jar 中类的类Main:测试内部平台调用效果
  TPAClassLoader.javaimport cn.hutool.core.lang.Console; import lombok.SneakyThrows;  import java.io.File; import java.io.FileNotFoundException; import java.net.URL; import java.net.URLClassLoader; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap;  /**  * 为加载三方平台 A 提供的 Jar 自定义的类加载器  *  * @since 2023/1/14 10:02  */ public class TPAClassLoader extends URLClassLoader {      /**      * 用于缓存相应平台的类加载器,防止重复创建和加载类,造成内存泄漏      */     private static final ConcurrentMap CLASS_LOADER_CACHE = new ConcurrentHashMap<>();       private TPAClassLoader(URL[] urls, ClassLoader parent) {         super(urls, parent);     }      /**      * 用于获取相应三方平台 Jar 包中的类,如果已经加载直接返回,未加载通过 TAPClassLoader 加载类,完成后返回      *      * @param internalPlatformCode 内部平台编码,例如:内部平台 A 的编码就是 A      * @param tapJarPath           为相应内部平台定制的三方平台 Jar 路径      * @param className            待获取类的全限定类名      * @return 类的 Class 对象      */     @SneakyThrows     public static Class<?> getClass(String internalPlatformCode, String tapJarPath, String className) {         TPAClassLoader classLoader = getInstance(internalPlatformCode, tapJarPath);         Console.log("获取内部平台 {} 的类:{}", internalPlatformCode, className);         return classLoader.loadClass(className);     }      /**      * 用于获取对应内部平台的类加载器,类加载器相对于内部平台是单例的,保证单例使用单例设计模式 DCL 的方式      *      * @param internalPlatformCode 内部平台编码,例如:内部平台 A 的编码就是 A      * @param tapJarPath           为相应内部平台定制的三方平台 Jar 路径      * @return 内部平台对应的类加载器      */     private static TPAClassLoader getInstance(String internalPlatformCode, String tapJarPath) throws Exception {         final String key = buildKey(internalPlatformCode, tapJarPath);         TPAClassLoader classLoader = CLASS_LOADER_CACHE.get(key);         if (classLoader != null) {             return classLoader;         }         synchronized (TPAClassLoader.class) {             classLoader = CLASS_LOADER_CACHE.get(key);             if (classLoader != null) {                 return classLoader;             }              File jarFile = new File(tapJarPath);             if (!jarFile.exists()) {                 throw new FileNotFoundException("未找到三方平台 A Jar 包文件:" + tapJarPath);             }             classLoader = new TPAClassLoader(new URL[]{jarFile.toURI().toURL()}, getSystemClassLoader());             Console.log("为内部平台 {} 创建类加载器:{}", internalPlatformCode, classLoader);             CLASS_LOADER_CACHE.put(key, classLoader);             return classLoader;         }     }      /**      * 用于生成缓存对应内部平台类加载器的 Key      *      * @param internalPlatformCode 内部平台编码,例如:内部平台 A 的编码就是 A      * @param tapJarPath           为相应内部平台定制的三方平台 Jar 路径      * @return 缓存 Key      */     private static String buildKey(String internalPlatformCode, String tapJarPath) {         return internalPlatformCode.concat("::").concat(tapJarPath);     } }
  Main.javaimport cn.hutool.core.lang.Console; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.ReflectUtil; import lombok.SneakyThrows;  import java.util.HashMap; import java.util.Map;  /**  * Main  *  * @author ZhaoHaichun  * @since 2023/1/14 10:34  */ public class Main {      /**      * 该 Map 只是测试使用,用于临时保持三方平台 A 提供的 Jar 包路径,实际开发会通过文件上传到服务器,然后获取上传路径,通过路径加载      */     private static final Map TPA_JAR_PATH_MAP = new HashMap<>();      private static final String TAP_ACCESS_SERVICE_NAME = "com.thirdparty.TPAAccessService";       static {         TPA_JAR_PATH_MAP.put("A", "C:UserszhaohDesktopTemptap_jarthird-party-A-for-A-1.0-SNAPSHOT.jar");         TPA_JAR_PATH_MAP.put("B", "C:UserszhaohDesktopTemptap_jarthird-party-A-for-B-1.0-SNAPSHOT.jar");     }       @SneakyThrows     public static void main(String[] args) {         for (int i = 0; i < 5; i++) {             // 用于随机生成待访问的内部平台             String internalPlatformCode = String.valueOf((char) RandomUtil.randomInt("A", "B" + 1));             // 通过访问的内部平台查询三方平台 A 为其提供的 Jar 路径             String jarPath = TPA_JAR_PATH_MAP.get(internalPlatformCode);             // 通过上述信息,使用相应的类加载器加载或直接获取类 "com.thirdparty.TPAAccessService"             Class<?> clazz = TPAClassLoader.getClass(internalPlatformCode, jarPath, TAP_ACCESS_SERVICE_NAME);             // 调用其相应的方法             ReflectUtil.invokeStatic(clazz.getMethod("send"));             Console.log("================================================================");         }     } }测试步骤
  编写完成上述代码后,按照下面步骤执行:使用 Maven package 打包项目:third-party-A-for-A、third-party-A-for-B将打包完成的 Jar 拷贝到测试目录,上面实例代码为:"C:UserszhaohDesktopTemptap_jar"目录下修改 Main 类静态代码块中的路径与 Jar 包路径一致执行 Main 类中的 main 方法
  输出结果如下:(每次输出可能不同)为内部平台 A 创建类加载器:com.ump.TPAClassLoader@568db2f2 获取内部平台 A 的类:com.thirdparty.TPAAccessService [A -> TPA] 密钥:AAAAAAAAAAA   ClassLoader:com.ump.TPAClassLoader@568db2f2 ================================================================ 获取内部平台 A 的类:com.thirdparty.TPAAccessService [A -> TPA] 密钥:AAAAAAAAAAA   ClassLoader:com.ump.TPAClassLoader@568db2f2 ================================================================ 为内部平台 B 创建类加载器:com.ump.TPAClassLoader@179d3b25 获取内部平台 B 的类:com.thirdparty.TPAAccessService [B -> TPA] 密钥:BBBBBBBBBBB   ClassLoader:com.ump.TPAClassLoader@179d3b25 ================================================================ 获取内部平台 B 的类:com.thirdparty.TPAAccessService [B -> TPA] 密钥:BBBBBBBBBBB   ClassLoader:com.ump.TPAClassLoader@179d3b25 ================================================================ 获取内部平台 A 的类:com.thirdparty.TPAAccessService [A -> TPA] 密钥:AAAAAAAAAAA   ClassLoader:com.ump.TPAClassLoader@568db2f2 ================================================================
  通过上面的输出结果可以看出:内部平台 A 和 B 分别只创建了一次类加载器创建完成类加载器后,后续均通过缓存中获取相应的类加载器在 Jar 包中 TPAAccessService 调用了 SendRequestProvider,而 SendRequestProvider 输出的日志中类加载器同加载 TPAAccessService 的类加载器相同,说明类加载传导规则内部平台 A 调用,输出的密钥是"AAAAAAAAAAA",B 调用输出的密钥是"BBBBBBBBBBB",说明为内部平台提供的 Jar 均加载到内存,而且通过类加载器实现了类的隔离

三星GalaxyS23发布不涨价押注中国市场望提振盈利集微网消息,三星今(2)日发布新版GalaxyS23,令人意外的是,尽管面对材料成本不断上涨的压力,三星未提价,新机配备更好的摄像头,比其前身更快的芯片,电池续航时间也更长。三星电我国已在入境人群中监测到双头犬毒株(CH。1。1),尚未传播CH。1。1于去年7月份在印度首次检出,其携带有Delt突变体的标志突变位点(L452R)突变毒株目前在全球67个国家和地区出现。目前比较严重的国家包括新西兰,英国,丹麦和新加坡等猪价涨势反扑,上涨逻辑是啥?要涨多久?2月2日猪价导读拨云见日,节后生猪市场愁云密布,猪价在多空拉扯下不断走低,而随着猪价顺势跌破14元公斤,市场情绪陡然变化,一方面,猪粮比值大幅回落,生猪下跌预警升级,市场对于收储的预期增强另一前有环江西高铁圈,今有环江西自贸区,江西你被谁抛弃?2013年央视一张环江西高铁圈让江西一夜成名,此后环江西现象层出不穷。如今,环江西现象又多一笔,那就是环江西自贸区。在自贸区遍地开花的今天,江西是目前还没有获批建设自贸区的10个省2022年中国光伏行业市场回顾及2023年发展前景预测分析中商情报网讯全球的光伏产业正处于风口,呈现井喷式的发展。从国内来看,我国以光伏发电为代表的新能源发展成效显著,装机规模稳居全球首位,发电量占比稳步提升,成本快速下降,已基本进入平价常德岳阳株洲湘潭首套房贷降息!贷款利率下限或进3阶段湖南银保监局新闻通气会现场。常德岳阳株洲湘潭已下调首套房按揭贷款利率2022年,湖南全年房地产贷款新增近500亿元,为498。8亿元。这是记者从2日召开的湖南银保监局新闻通气会上了中央决定徐鹏任中国一重总经理(附简历)据中国一重官网消息,2023年2月1日上午,中国一重集团有限公司召开领导班子(扩大)会议。受中央组织部领导委托,中央组织部有关干部局负责同志宣布了中央关于中国一重集团有限公司总经理鸿晔科技终止创业板IPO保荐机构为海通证券来源中国经济网中国经济网北京2月2日讯据深交所网站昨晚消息,深交所决定终止对上海鸿晔电子科技股份有限公司(以下简称鸿晔科技)首次公开发行股票并在创业板上市的审核。2023年1月16大股东与二股东内斗,厨邦酱油何去何从?厨邦和美味鲜想必大家都知道,有些人应该也吃过,但是中炬高新估计听说过的不多。这是一家投资为主的公司,三十年来,投资的行业涉及动力电池房地产精工汽配运输调味食品等。投资的大部分公司,中国经济重启,是全球大威胁?美媒改了离谱标题中国经济重启是全球经济通胀的下一个大威胁,1月31日,美媒彭博社以这样一个耸人听闻的标题,发布了一篇与中国经济相关的报道。彭博社报道原标题该报道的大体内容是围绕中国防疫政策调整后,中国乒乓之绝地反击撤档,这个电影到底怎样?后续会怎么安排首映现场,邓超数度哽咽,直言这次拍摄电影,压力真的非常大。面对困境,一个不被看好的人和一群不被看好的队员如何走出低谷,它本身辐射出来的力量是很强的。这个故事给了我们力量,希望也能够
氨基酸维生素,这些补药吃得越多越好吗?绝对不是的!在现实生活中,因吃药而导致的肝损伤肾衰竭及耳聋的新闻屡屡发生,据有关数据统计,每年我国约有250万人因吃错药而导致自己的健康受损如果您或您的家人好友在服用如下几种药物,315动态丨沃尔玛一门店售兽药残留的草鱼,被罚5。1万元红星资本局3月7日消息,近日,沃尔玛(珠海)商业零售有限公司普宁广达北路分店被普宁市市场监督管理局行政处罚。据国家企业信用信息公示系统,该门店销售恩诺沙星项目(兽药残留)不合格的草孕期发烧对胎儿有影响吗?退烧药只能用对乙酰氨基酚吗?一次说清今年25岁的蒙蒙是一名准妈妈,前些年通过闺蜜的介绍,结识了如今的老公。两人从相识到相知,最后完满地步入了婚姻的殿堂。结婚后不久,蒙蒙就顺利怀上了宝宝。在孕期期间,蒙蒙的老公给予了她头条里想赚钱,得先知道怎么玩,了解基本常识小白白看过来越来越多的人来头条耕耘,都想着,既能施展自己的小才能,又能乘自媒体的东风,发点小财,亦或是赚个早餐钱。也是啊!本来钱就难赚,又遇三年疫情,把人都逼的苦逼哈哈的。居家隔离的阶段,自媒西部第2!时隔17年再破纪录!NBA最强黑马诞生了猜猜西部第二是谁?萨克拉门托国王!目前国王队40胜26负,仅次于掘金,高居西部第二!值得一提的是,这是国王自200506赛季(44胜38负)以来,近17年来首次单赛季拿到40胜。常完败!太阳五虎9025,克莱半场33分,新纪录诞生,西部第五易主北京时间2023年3月14日,今日NBA比赛,35胜33负的勇士在主场迎战37胜30负的太阳,勇士威金斯库明加缺阵,首发库里克莱迪温琴佐追梦卢尼,太阳杜兰特缺阵,首发保罗布克奥科吉新赛季女超联赛争冠集团角逐激烈年轻小花争相涌现来源人民网原创稿2023赛季女超联赛自3月4日起掀开新赛季的帷幕,3月12日第一阶段正式战罢。时隔三年重启主客场赛制,扩容后的12支球队在两周时间里共进行了三轮18场比赛的较量,展最高300元!文旅消费券,明天开抢!第三轮文旅消费券要来啦!就在明天!请大家定好闹钟,不要错过!3月14日(周二)上午10点开抢!从住宿餐饮线路到文娱样样齐全福利满满!抢券攻略新闻多看点闭幕!从现在起,全党全国人民的美国不应援助乌克兰,说这句话的不是一般人,或是美国下任总统巴赫穆特绞肉机战况激烈,据最新消息,俄罗斯私营军事集团瓦格纳已经控制了当地的大型工业区。乌克兰总统泽连斯基表示前线战事异常艰难,已经被俄军切断了供给线。可见,眼下泽连斯基需要的是西四位警花甘愿做他情妇,被称为天津武爷,他到底是谁?随着现在反腐高压不断加大,不断有贪官落马,有进行权色交易的,有贪污受贿的,但是有一个公安局局长,四位警花甘愿沦为他的情夫,只为给他传宗接代,这个人就是人称天津武爷的武长顺。武爷这个3月14日周二竞彩赛事比分预测欧冠波尔图VS国际米兰005波尔图vs国际米兰0400波尔图本赛季葡超与榜首的本菲卡之间已经拉开了八分的分差,而且也只比第三名的布拉加多了2分,多线作战情况下,球队还是暴露出阵容厚度不够,欧冠首回合客场