网易首页 > 网易号 > 正文 申请入驻

手动部署jar包,太low了!动态上传包热部署,真爽!

0
分享至

Java精选面试题(微信小程序):5000+道面试题和选择题,包含Java基础、并发、JVM、线程、MQ系列、Redis、Spring系列、Elasticsearch、Docker、K8s、Flink、Spark、架构设计、大厂真题等,在线随时刷题!

近期开发系统过程中遇到的一个需求,系统给定一个接口,用户可以自定义开发该接口的实现,并将实现打成jar包,上传到系统中。系统完成热部署,并切换该接口的实现。

定义简单的接口

这里以一个简单的计算器功能为例,接口定义比较简单,直接上代码。

public interface Calculator {     int calculate(int a, int b);     int add(int a, int b); }
该接口的一个简单的实现

考虑到用户实现接口的两种方式,使用spring上下文管理的方式,或者不依赖spring管理的方式,这里称它们为注解方式和反射方式。calculate方法对应注解方式,add方法对应反射方式。计算器接口实现类的代码如下:

@Service publicclass CalculatorImpl implements Calculator {     @Autowired     CalculatorCore calculatorCore;     /**      * 注解方式      */     @Override     public int calculate(int a, int b) {         int c = calculatorCore.add(a, b);         return c;     }     /**      * 反射方式      */     @Override     public int add(int a, int b) {         returnnew CalculatorCore().add(a, b);     } }

这里注入CalculatorCore的目的是为了验证在注解模式下,系统可以完整的构造出bean的依赖体系,并注册到当前spring容器中。CalculatorCore的代码如下:

@Service public class CalculatorCore {     public int add(int a, int b) {         return a+b;     } }
反射方式热部署

用户把jar包上传到系统的指定目录下,这里定义上传jar文件路径为jarAddress,jar的Url路径为jarPath。

private static String jarAddress = "E:/zzq/IDEA_WS/CalculatorTest/lib/Calculator.jar"; private static String jarPath = "file:/" + jarAddress;

并且可以要求用户填写jar包中接口实现类的完整类名。接下来系统要把上传的jar包加载到当前线程的类加载器中,然后通过完整类名,加载得到该实现的Class对象。然后反射调用即可,完整代码:

/**  * 热加载Calculator接口的实现 反射方式,公众号Java精选  */ public static void hotDeployWithReflect() throws Exception {     URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL(jarPath)}, Thread.currentThread().getContextClassLoader());     Class clazz = urlClassLoader.loadClass("com.nci.cetc15.calculator.impl.CalculatorImpl");     Calculator calculator = (Calculator) clazz.newInstance();     int result = calculator.add(1, 2);     System.out.println(result); }
注解方式热部署

如果用户上传的jar包含了spring的上下文,那么就需要扫描jar包里的所有需要注入spring容器的bean,注册到当前系统的spring容器中。其实,这就是一个类的热加载+动态注册的过程。

直接上代码:

/**  * 加入jar包后 动态注册bean到spring容器,包括bean的依赖  */ public static void hotDeployWithSpring() throws Exception {     Set classNameSet = DeployUtils.readJarFile(jarAddress);     URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL(jarPath)}, Thread.currentThread().getContextClassLoader());     for (String className : classNameSet) {         Class clazz = urlClassLoader.loadClass(className);         if (DeployUtils.isSpringBeanClass(clazz)) {             BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);             defaultListableBeanFactory.registerBeanDefinition(DeployUtils.transformName(className), beanDefinitionBuilder.getBeanDefinition());         }     } }

在这个过程中,将jar加载到当前线程类加载器的过程和之前反射方式是一样的。然后扫描jar包下所有的类文件,获取到完整类名,并使用当前线程类加载器加载出该类名对应的class对象。判断该class对象是否带有spring的注解,如果包含,则将该对象注册到系统的spring容器中。

DeployUtils包含读取jar包所有类文件的方法、判断class对象是否包含sping注解的方法、获取注册对象对象名的方法。代码如下:

/**  * 读取jar包中所有类文件  */ public static Set   readJarFile(String jarAddress) throws IOException {     Set classNameSet =  new HashSet<>();     JarFile jarFile = new JarFile(jarAddress);     Enumeration entries = jarFile.entries(); //遍历整个jar文件     while (entries.hasMoreElements()) {         JarEntry jarEntry = entries.nextElement();         String name = jarEntry.getName();         if (name.endsWith(".class")) {             String className = name.replace(".class", "").replaceAll("/", ".");             classNameSet.add(className);         }     }     return classNameSet; }

/**  * 方法描述 判断class对象是否带有spring的注解  */ public static boolean isSpringBeanClass(Class cla) {     if (cla == null) {         returnfalse;     }     //是否是接口     if (cla.isInterface()) {         returnfalse;     }     //是否是抽象类     if (Modifier.isAbstract(cla.getModifiers())) {         returnfalse;     }     if (cla.getAnnotation(Component.class) != null) {         returntrue;     }     if (cla.getAnnotation(Repository.class) != null) {         returntrue;     }     if (cla.getAnnotation(Service.class) != null) {         returntrue;     }     returnfalse; }

/**  * 类名首字母小写 作为spring容器beanMap的key  */ public static String transformName(String className) {     String tmpstr = className.substring(className.lastIndexOf(".") + 1);     return tmpstr.substring(0, 1).toLowerCase() + tmpstr.substring(1); }
删除jar时,需要同时删除spring容器中注册的bean

在jar包切换或删除时,需要将之前注册到spring容器的bean删除。spring容器的bean的删除操作和注册操作是相逆的过程,这里要注意使用同一个spring上下文。

代码如下:

/**  * 删除jar包时 需要在spring容器删除注入  */ public static void delete() throws Exception {     Set classNameSet = DeployUtils.readJarFile(jarAddress);     URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL(jarPath)}, Thread.currentThread().getContextClassLoader());     for (String className : classNameSet) {         Class clazz = urlClassLoader.loadClass(className);         if (DeployUtils.isSpringBeanClass(clazz)) {             defaultListableBeanFactory.removeBeanDefinition(DeployUtils.transformName(className));         }     } }
测试

测试类手动模拟用户上传jar的功能。测试函数写了个死循环,一开始没有找到jar会抛出异常,捕获该异常并睡眠10秒。这时候可以把jar手动放到指定的目录下。

代码如下:

 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");     DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();     while (true) {         try {               hotDeployWithReflect(); //            hotDeployWithSpring(); //            delete();             } catch (Exception e) {                 e.printStackTrace();                 Thread.sleep(1000 * 10);             }         }

作者:zhangzhiqiang_0912

https://blog.csdn.net/zhangzhiqiang_0912

公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者。如有侵权,请联系,笔者会第一时间删除处理!

最近有很多人问,有没有读者交流群!加入方式很简单,公众号Java精选,回复“加群”,即可入群!

文章有帮助的话,点在看,转发吧!

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
长实集团再发澄清公告:网传照片不实,李嘉诚健康情况良好

长实集团再发澄清公告:网传照片不实,李嘉诚健康情况良好

红星新闻
2026-10-22 12:14:17
黑龙江一男子将3000万存银行,银行承诺3年利息为4%,每年120万利息,可第三年只给105万利息,还有15万元不给了,男子把银行告上法庭!

黑龙江一男子将3000万存银行,银行承诺3年利息为4%,每年120万利息,可第三年只给105万利息,还有15万元不给了,男子把银行告上法庭!

背包旅行
2026-10-22 10:04:54
断舍离上百件衣服总结:秋冬季别买这8种衣服,最后都闲置吃灰!

断舍离上百件衣服总结:秋冬季别买这8种衣服,最后都闲置吃灰!

抠搜侠
2026-10-21 14:05:27
海航6.66万元顺心卡流入二手市场,员工倒贴求开卡,每张返现超2000元

海航6.66万元顺心卡流入二手市场,员工倒贴求开卡,每张返现超2000元

蓝鲸新闻
2026-10-21 11:40:39
彻底疯狂了!日本这回是真憋了个大招。

彻底疯狂了!日本这回是真憋了个大招。

果妈聊娱乐
2026-10-21 08:14:20
90岁钟南山现状:心脏装过支架,还能小跑开球,如今又有新身份

90岁钟南山现状:心脏装过支架,还能小跑开球,如今又有新身份

阿讯说天下
2026-10-21 17:24:18
特朗普万没料到,先等来的不是俄油供应,而是背叛

特朗普万没料到,先等来的不是俄油供应,而是背叛

时尚的弄潮
2026-10-21 10:46:54
克林顿自传揭秘中国大使馆被误炸经过:实际上命中了预定目标!

克林顿自传揭秘中国大使馆被误炸经过:实际上命中了预定目标!

舆图看世界
2026-10-17 15:50:04
贵州30岁美女妈妈“小奇奇”去世!刚刚诞下孩子,待产前一天晚上还在修改论文,农科院研究生毕业

贵州30岁美女妈妈“小奇奇”去世!刚刚诞下孩子,待产前一天晚上还在修改论文,农科院研究生毕业

裕丰娱间说
2026-10-22 17:15:28
今晨北京多区气温跌破冰点,未来10天北方大部气温偏低

今晨北京多区气温跌破冰点,未来10天北方大部气温偏低

新京报
2026-10-22 15:50:04
“盘石创始人田宁疑似失联”,杭州警方发布警情通报

“盘石创始人田宁疑似失联”,杭州警方发布警情通报

政知新媒体
2026-10-22 13:17:21
台湾县市长选举最新预测:国民党有望夺下16席,蓝绿决战在台北市

台湾县市长选举最新预测:国民党有望夺下16席,蓝绿决战在台北市

孤单是寂寞的毒
2026-10-21 13:21:46
不出意外的话,下半年开始,房价、金价、物价或都迎来大洗牌

不出意外的话,下半年开始,房价、金价、物价或都迎来大洗牌

云居历史
2026-10-22 13:26:17
从第12年到第13年,争吵停了,婚姻也停了

从第12年到第13年,争吵停了,婚姻也停了

宅家小欢喜
2026-10-21 18:41:35
恩爱40年难抵残酷现实?65岁刘德华近况曝光,14岁女儿成遗憾

恩爱40年难抵残酷现实?65岁刘德华近况曝光,14岁女儿成遗憾

菲儿爱蛋糕
2026-10-20 17:43:22
卡拉格:B费的发言简直是耻辱,没有卡里克他拿不了赛季最佳

卡拉格:B费的发言简直是耻辱,没有卡里克他拿不了赛季最佳

懂球帝
2026-10-22 06:51:11
小天赐,终为父母当年的“冲动”买了单,年仅7岁活得不像个小孩

小天赐,终为父母当年的“冲动”买了单,年仅7岁活得不像个小孩

竖起来的三
2026-10-21 17:07:09
前5名只差4分!冲甲大战进入最后3轮争夺,山东泰山B队能否实现逆袭?

前5名只差4分!冲甲大战进入最后3轮争夺,山东泰山B队能否实现逆袭?

实事球是
2026-10-22 18:56:14
揭秘“梅西私人飞机”!堪称飞行宫殿,抵达奥维耶多,球迷接机

揭秘“梅西私人飞机”!堪称飞行宫殿,抵达奥维耶多,球迷接机

汪星人哟
2026-10-22 20:33:53
NS2也被破解了!惨无人道 任天堂还是没防住

NS2也被破解了!惨无人道 任天堂还是没防住

游民星空
2026-10-22 16:17:31
2026-10-22 21:16:49
Java精选
Java精选
一场永远也演不完的戏
1803文章数 3859关注度
往期回顾 全部

科技要闻

腾讯云谷歌紧急行动!互联网安全出大事

头条要闻

坠亡2岁男童父亲望维持婚姻:每月给妻子1万 父母出6千

头条要闻

坠亡2岁男童父亲望维持婚姻:每月给妻子1万 父母出6千

体育要闻

卢卡:伦德伯格,欢迎来到NBA

娱乐要闻

芭莎盛典,张小斐因救场实现口碑暴涨

财经要闻

数据中心建设延期潮 谁受伤、谁受益?

汽车要闻

搭城市NOA/续航555KM 捷达M6上市售7.98万起

态度原创

时尚
数码
亲子
本地
手机

“廓形穿衣法”太火了!这5个法则松弛又好看

数码要闻

Akko《诡秘之主》联名5098 V5三模机械键盘发售,券后359元

亲子要闻

儿童得了溃疡性结肠炎更严重?仍存在持续未被满足的治疗需求!全新治疗方式临床研究迎来新进展

本地新闻

总书记刚来过的这座城,藏着火山秋原

手机要闻

影石Ace Pro 3运动相机现身FCC认证数据库,有望近期发布

无障碍浏览 进入关怀版