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

手动部署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.

相关推荐
热点推荐
与英格兰队一役,哈兰德带球1次总带球距离4.9米,总推进距离3.6米

与英格兰队一役,哈兰德带球1次总带球距离4.9米,总推进距离3.6米

红星新闻
2026-07-12 10:15:16
《给阿嬷的情书》新加坡票房破纪录!南都曾对话片尾侨批作者

《给阿嬷的情书》新加坡票房破纪录!南都曾对话片尾侨批作者

南方都市报
2026-07-12 12:24:04
伊朗打击科威特巴林的美军设施

伊朗打击科威特巴林的美军设施

界面新闻
2026-07-12 12:13:49
黄有龙:将与赵薇结婚当生意做,离异后还与前妻有联系

黄有龙:将与赵薇结婚当生意做,离异后还与前妻有联系

细品名人
2026-07-12 07:22:06
辉腾鞋业28死事件发酵!网友:年运营成本至少2000万,5层7000平米的工厂,效益非常不错了

辉腾鞋业28死事件发酵!网友:年运营成本至少2000万,5层7000平米的工厂,效益非常不错了

曹莽看世界
2026-07-11 15:16:00
昔日旅游胜地沦为黄赌毒重灾区,灰色交易猖獗,比缅北更恐怖

昔日旅游胜地沦为黄赌毒重灾区,灰色交易猖獗,比缅北更恐怖

范櫳舍长
2026-07-11 10:18:11
国家级院士提醒:过了60岁,体检主要查这6项,别随便乱查

国家级院士提醒:过了60岁,体检主要查这6项,别随便乱查

路医生健康科普
2026-07-10 20:35:03
台风“巴威”最新路径预报出炉

台风“巴威”最新路径预报出炉

财联社
2026-07-12 06:24:29
阿根廷晋级,世界杯4强出炉

阿根廷晋级,世界杯4强出炉

第一财经资讯
2026-07-12 12:19:04
斯蒂芬·金88%高分新片上线,HBO这回抢到了

斯蒂芬·金88%高分新片上线,HBO这回抢到了

时光慢旅人
2026-07-11 00:31:56
桑德-贝格:被吹的那球应该算有效;这是我生涯最酷的旅程

桑德-贝格:被吹的那球应该算有效;这是我生涯最酷的旅程

懂球帝
2026-07-12 10:54:05
深圳大厂倒闭,950人三天失业,中年打工人的天塌了?

深圳大厂倒闭,950人三天失业,中年打工人的天塌了?

一口娱乐
2026-07-12 10:04:55
吃相太难看!周星驰砸3亿的电影上映不到一天,令人恶心一幕上演

吃相太难看!周星驰砸3亿的电影上映不到一天,令人恶心一幕上演

观察鉴娱
2026-07-12 11:07:10
A股:刚刚,国务院最新重磅部署,两大行业或将爆发,下周是关键

A股:刚刚,国务院最新重磅部署,两大行业或将爆发,下周是关键

云鹏叙事
2026-07-12 08:51:04
25岁男子隐私部位被割断,鲜血浸透裤管,医生6小时接回!母亲红了眼眶:如果不是你们,我儿子一生就毁了

25岁男子隐私部位被割断,鲜血浸透裤管,医生6小时接回!母亲红了眼眶:如果不是你们,我儿子一生就毁了

掌上春城
2026-07-11 12:32:15
对于下周一A股,紧急提醒三点:第一,4074点绝不是最高点!

对于下周一A股,紧急提醒三点:第一,4074点绝不是最高点!

虎哥闲聊
2026-07-12 09:20:39
7月11日俄乌最新:川普跨出重要一步

7月11日俄乌最新:川普跨出重要一步

西楼饮月
2026-07-11 18:26:23
鹿晗在司晓迪船上很卖力!?

鹿晗在司晓迪船上很卖力!?

八卦疯叔
2026-07-11 18:56:43
台风“巴威”已离开浙江,进入安徽宁国市境内,强热带风暴级,中心附近最大风力10级(28米/秒)

台风“巴威”已离开浙江,进入安徽宁国市境内,强热带风暴级,中心附近最大风力10级(28米/秒)

极目新闻
2026-07-12 11:59:24
含金量十足,本届世界杯四强=上届世界杯决赛+上届欧洲杯决赛

含金量十足,本届世界杯四强=上届世界杯决赛+上届欧洲杯决赛

懂球帝
2026-07-12 11:47:18
2026-07-12 12:56:49
Java精选
Java精选
一场永远也演不完的戏
1796文章数 3859关注度
往期回顾 全部

科技要闻

苹果诉OpenAI细节:一句“笑死”刺痛库克

头条要闻

哈兰德父亲看台上做不雅手势 网友:在隔空挑衅老对手

头条要闻

哈兰德父亲看台上做不雅手势 网友:在隔空挑衅老对手

体育要闻

被3个队友锁死,哈兰德以最憋屈的方式出局

娱乐要闻

迪丽热巴估计都无语了 亲自下场辟

财经要闻

美联储和市场将走向何方?

汽车要闻

预售权益价11.78万起 五菱星光L将于7月16日上市

态度原创

本地
亲子
手机
游戏
公开课

本地新闻

重庆人有自己的避暑桃花源 | 夏天就去「酉」风的地方!

亲子要闻

令韩国商家无语的外卖备注:孕妇吃的,请多给一些…

手机要闻

iPhone Fold双电池组合4883mAh 容量不及直板机

《黑色行动》两作PS版在线玩家超全平台《黑色行动7》

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版