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

变态需求给定一个接口,用户自定义动态实现上传热部署,咋搞?

  近期开发系统过程中遇到的一个需求,系统给定一个接口,用户可以自定义开发该接口的实现,并将实现打成jar包,上传到系统中。系统完成热部署,并切换该接口的实现
  定义简单的接口
  这里以一个简单的计算器功能为例,接口定义比较简单,直接上代码。  public interface Calculator {     int calculate(int a, int b);     int add(int a, int b); } 该接口的一个简单的实现
  考虑到用户实现接口的两种方式,使用spring上下文管理的方式,或者不依赖spring管理的方式,这里称它们为注解方式和反射方式。 calculate 方法对应注解方式,add方法对应反射方式。
  这里推荐一个 Spring Boot 基础教程:
  https://github.com/javastacks/spring-boot-best-practice
  计算器接口实现类的代码如下:  @Service public class 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) {         return new 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接口的实现 反射方式  */ 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容器中。其实,这就是一个类的热加载+动态注册的过程。另外,最新 Spring 面试题整理好了,大家可以在Java面试库小程序在线刷题。
  直接上代码:  /**  * 加入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) {         return false;     }     //是否是接口     if (cla.isInterface()) {         return false;     }     //是否是抽象类     if (Modifier.isAbstract(cla.getModifiers())) {         return false;     }     if (cla.getAnnotation(Component.class) != null) {         return true;     }     if (cla.getAnnotation(Repository.class) != null) {         return true;     }     if (cla.getAnnotation(Service.class) != null) {         return true;     }     return false; } /**  * 类名首字母小写 作为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);             }         }
  看完,涨姿势了没?
  原文链接:https://blog.csdn.net/zhangzhiqiang_0912/article/details/106980080

汉武帝刘彻一场幻觉引起的巫蛊皇宫血案公元前92年,汉武帝坐在建章宫内养神,迷神之际,感觉有一名带剑的男子走进中龙华门,于是他猛地站起身,大声叫喊来人,抓刺客,他一喊,那人仿佛消失一般不见了,侍卫们一拥而入,整个建章宫良缘(全集)在清朝年间,江苏按察使有一个小儿子叫黄有为。这个黄有为啊,从小就聪明伶俐。饱读诗书。在17岁的时候就参加了乡试,并且考取了借员。由于他家庭也不错,人也帅气,又颇有前途,上门来说亲的AI绘画算不算艺术据人民网报道,在2022世界人工智能大会上,Tiamat人工智能艺术团队的展位吸引着好奇的观众,他们中有不少人是首次尝试AI绘画,普通人竟能像名家一样画画,呈现毕加索蒙克莫奈的画风徕卡旗舰手机LeitzPhone2发布一英寸大底主摄,售价过万在去年6月,徕卡与日本软银公司联合推出了首款智能手机LeitzPhone1,得益于徕卡,该机在当时就有着相当不错的性能和摄影表现。而在近日,软银发布了全新一代的徕卡旗舰手机LeitiPhone只能排第二,今年双十一销量冠军大爆冷双十一已进入尾声,大家关心的手机销量情况也基本已确定,就和预测的一样,苹果依然是最大赢家,根据京东双11手机竞速排行榜,销量前十中,iPhone霸占四席,分别是iPhone14iP目前出色的3款国产手机,性能强悍价格良心,还买什么iPhone14?现在国产手机各方面做的真的非常不错,真的不比苹果差,目前这3款手机性能十分出色,性价比也很高,还买什么iPhone14?vivoX70Pro性能方面,搭载了骁龙888Plus芯片增Web3。0是什么?Web3。0一夜之间传遍了整个大街小巷,那什么是Web3。0呢?这就得从Web1。0开始说起。1991年第一个网址的出现,就标志着我们迈进了Web1。0时代,特点是只读,Reado薇娅被罚13亿后,投资的公司要来A股了雷军雷布斯是国内互联网创业投资界典型人物,无论是雷军这个名字,还是小米这个品牌,到哪都是自带光环自带流量。以直播带货封神的薇娅,本名黄薇,因为巨额偷税漏税让她跌落神坛,目前也是一个智能制造时代,服装企业如何实现智能制造系统转型升级?什么是智能制造工厂好比一台复杂的汽车,需要各个部门高效协同,统一行动,才能使管理效率和生产效率达到平衡智能化就是透过网络让企业内部各关联部门,生产各关联环节及要素互连,实现高效协同华为麒麟芯片被拒代工之后,台积电5nm利用率能撑多久?众所周知,目前全球5纳米芯片制程,只有台积电和三星能完成生产,在科技无国界之时,三星在供应自己三星手机使用的同时,也帮助苹果代工生产芯片,台积电就纯粹的多了,就是一家代加工企业,客花钱不手软!沙特王储将造访首尔,订了乐天酒店400间房沙特阿拉伯王储穆罕默德本萨勒曼将在17至18日造访韩国首尔,下榻首尔繁华地段的乐天酒店,讨论从智慧城市到核能基建等议题。沙特王储此行也是花钱不手软,比如在有1058个客房的乐天酒店
是鲁医生一巴掌,毁掉两个家庭还是子不教,毁掉两个家庭?作为家长来说,不可能24小时待在小孩的身边。因此,一定要教育他们怎么保护自己,即不能被别人伤害,也不能去伤害别人。这是作为一个家长,对孩子和对社会最起码的义务和责任。两个小孩子,在乌鲁木齐市入列全国智能建造试点城市视频加载中试点预期目标主要包括三个方面一是加快推进科技创新,提升建筑业发展质量和效益。重点围绕数字设计智能生产智能施工建筑产业互联网建筑机器人智慧监管六大方面,挖掘一批典型应用场景油价调整消息今天11月15日,调价后全国9295号汽油限价OPEC再次下调全球石油需求增长预期,此前的多次报告已经强调过全球经济增长,石油需求预期在今年也已相继下调了四次,加上美联储放缓收紧市场并不代表加息的停止,美元指数周一大涨,新一周双11收官长三角三省一市的购买力都进了全国前十今天(11月12日)零点,热闹了将近一个月的双11正式收官。虽然今年天猫与京东这两个电商平台均未公布成交总额。不过,天目新闻记者从京东了解到,截至11月11日23时59分,京东超越沙洲日记红色种子,向阳而生11月13日星期日多云转晴今天,趁着这初冬暖阳,我们陪同92岁,有着70年党龄的老父亲去半条被子故事发生地汝城沙洲看看。前些天我一提议,就得到了家里人的赞同,几个小孩子们得知后也都vivoX90Pro跑分出现搭载高通骁龙8Gen2芯片在今年,vivo发布了旗下的旗舰手机系列vivoX80系列,但是据相关报道称,今年不会推出vivoX80Pro而是直接推出vivoX90系列引起不少消费者关注。就在今日,据相关媒体IBM发布最新量子计算芯片联发科T8005G基带芯片发布芯闻速递两分钟了解芯片大事IBM发布最新量子计算芯片IBM在IBM量子峰会上发布了其最新量子计算芯片鱼鹰(Ospreychip)。这款芯片具备433个量子比特,其数量是去年推出的127个量大疆上架官翻无人机首款毫米波掌机鸿蒙3。0名单iQOO11跑分HarmonyOS3正式版最新升级名单昨日,HarmonyOS官微发布了最新的升级公告。本次共有HUAWEIP40HUAWEIMate30等15款产品开放HarmonyOS3正式版怎样的朋友才算得上是真正的朋友朋友一生一起走,那些日子不再有,一句话,一辈子,一生情,一杯酒朋友不曾孤单过,一声朋友你会懂,还有伤,还有痛,还要走,还有我。这是周华健演唱的朋友中的歌词,我们应该耳熟能详。每当听晚年生活是退休后种下的果,让自己持续增值才是最好的活法很多人退休后,自以为是,最终在晚年的时候,过成了孤家寡人,其实这是有原因的。很多人退休后无所事事,闲着,睡到自然醒,到处大吃大喝,聚会串门,小区里公园里打牌,跳广场舞,家不管,饭不最高可贷60万济宁市住房公积金贷款首付比例下调资料图大众网海报新闻记者尹荣耀济宁报道日前,记者从济宁市住房公积金中心了解到,济宁市住房公积金贷款首付比例下调,贷款额度由此前的最高40万,提高至最高可贷至60万。政策调整后,职工