Java如何自定义类加载器实现类隔离
发布时间:2023-03-16 11:49:56 所属栏目:教程 来源:
导读:这篇“Java怎么自定义类加载器实现类隔离”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来
这篇“Java怎么自定义类加载器实现类隔离”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java怎么自定义类加载器实现类隔离”文章吧。 一、背景 某服务需要连接操作多种组件(每种组件可能有多个版本),如kafka、mongodb、es、mysql等等,并且后续需要适配更多的组件。 Java怎么自定义类加载器实现类隔离 主要难点:连接操作多组件多版本,且同种组件的不同版本所依赖的jar包可能不一样,操作源码也可能发生改变,项目无法直接依赖jar包,会产生类冲突 二、解决思路 由于每种组件的不同版本所依赖的jar包不同,我们可以借鉴tomcat的实现方式,通过自定义类加载器打破双亲委派机制来实现类隔离,从而达到操作多组件多版本的目的。 Java怎么自定义类加载器实现类隔离 2.1 创建依赖所在目录 针对每一种组件我们创建一个目录,比如/data/kafka、/data/mongodb、/data/es等,且每种组件的不同版本创建对应的子目录,比如/data/kafka/0.10、/data/kafka/0.11,目录结构如下 | ----/data | --------/kafka | ------------/0.10 | ------------/0.11 | --------/MysqL | ------------/5.7 | ------------/8.0 | ... 把每种组件不同版本对应的依赖包放在各个子目录下面。 2.2 定义操作接口 在common公共模块中定义一个接口AbstractOperator,该接口定义一些通用方法,如下: public interface Operator { /** * 测试连接 * @param connectionInfo * @return */ boolean testConnection(String connectionInfo); /** * 获取组件版本 * @return */ String getVersion(String connectionInfo); } 再定义各种组件的接口,如KafkaOperator、MysqLOperator等,使其继承该通用接口。组件接口内部包含一些组件自身的操作,如KafkaOperator中定义了getTopics、createtopic、deletetopic等方法。代码如下: public interface KafkaOperator extends Operator{ /** * 获取topic列表 * @param connectionInfo * @return */ List<String> getTopics(String connectionInfo); /** * 创建topic * @param connectionInfo * @param topic * @return */ boolean createtopic(String connectionInfo, String topic); /** * 删除topic * @param connectionInfo * @param topic * @return */ boolean deletetopic(String connectionInfo, String topic); } 2.3 编写并构建业务包 大致步骤如下: 1.针对每种组件的不同版本,可以在项目下新建一个模块,该模块依赖common公共模块 2.创建入口类com.kamier.Entry(所有组件的不同版本的入口类的全限定名统一为com.kamier.Entry),并实现对应的组件接口,比如Kafka的0.10版本,那么就实现KafkaOperator接口。 Java怎么自定义类加载器实现类隔离 3.编写业务逻辑代码 public class Entry implements KafkaOperator { @Override public List<String> getTopics(String connectionInfo) { return null; } @Override public boolean createtopic(String connectionInfo, String topic) { return false; } @Override public boolean deletetopic(String connectionInfo, String topic) { return false; } @Override public boolean testConnection(String connectionInfo) { return false; } @Override public String getVersion(String connectionInfo) { return null; } } 4.打成jar包 5.将jar包放在对应的目录下,与依赖包同级,如/data/kafka/0.10 2.4 自定义类加载器 经过前面的准备工作,组件的每个版本的目录下都有了相应的依赖包和业务包。 开始编写一个自定义类加载器继承urlclassloader,重写loadClass方法,优先加载当前类加载器路径下的class来打破双亲委派模式,代码如下 public static class MyClassLoader extends urlclassloader { public MyClassLoader(URL[] urls) { super(urls); } public Class<?> loadClass(String name) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 先检查当前类加载器是否已经装载该类 Class<?> c = findLoadedClass(name); if (c == null) { try { // 在当前类加载器的路径下查找 c = findClass(name); } catch (ClassNotFoundException e) { // 说明在当前类加载器的路径下没有找到 } if (c == null) { // 走双亲委派机制 if (getParent() != null) { c = getParent().loadClass(name); } } } return c; } } } 针对每种组件的不同版本,我们创建与其对应的自定义类加载器,并将该版本对应目录下的所有jar包(包括依赖包和业务包)的URL传入。 2.5 主流程步骤 步骤如下: 当我们从页面上接收到一个获取Kafka(版本为0.10)topic列表的请求时,先判断是否已经初始化过Kafka(0.10版本)的类加载器,如果还未初始化,则进行类加载器的初始化。 URL[] urls = null; File dir = new File("/data/kafka/0.10"); if (dir.isDirectory()) { File[] files = dir.listFiles(); urls = new URL[files.length]; for (int i = 0; i < files.length; i++) { urls[i] = files[i].toURL(); } } MyClassLoader contextClassLoader = new MyClassLoader(urls); 通过类加载器加载入口类com.kamier.Entry并实例化,通过反射调用对应的方法(组件与其对应的方法列表可以统一维护在数据库中)。 Class loadClass = contextClassLoader.loadClass("com.kamier.Entry"); Object entry = loadClass.newInstance(); Method method = loadClass.getDeclaredMethod("getTopics"); List<String> a = (List) method.invoke(entry, 参数); 获取到结果并返回。 (编辑:汽车网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
推荐文章
站长推荐