星空下的程序猿 2021-12-14 16:01 采纳率: 0%
浏览 2006
已结题

springboot动态加载第三方jar包,可随时卸载和添加jar包

类似于微服务架构那样,但是不使用微服务架构。动态加载第三方jar包,在项目不停止运行的情况下,可随时卸载和添加jar包。
我使用URLClassLoader实现,但是jar包中有关spring的所有注解都使用不了,@Autowired获取不到实体类,@Value获取不到配置文件中的配置
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("file:D:/jar/uin-msggateway-lianlu-0.0.1-SNAPSHOT.jar"),new URL("file:D:/jar/uin-msggateway-ronglian-0.0.1-SNAPSHOT.jar")});

  • 写回答

17条回答 默认 最新

  • lkx444368875 2021-12-14 18:47
    关注
    获得12.00元问题酬金

    我这里提供一个实现的思路作为参考吧,想要实现你目前的功能的话:

    加载

    1. 首先将bean工厂先持有起来,作为父类工厂。
    2. 另外构建一个插件管理器,这个管理器负责动态加载、卸载jar的管理,并持有bean工厂的实例。【相当于一个子工厂】

      开始构建jar中的实例,分析实例的元数据【接口、父类等等】

    3. 1 读取jar中的实例[大鹏cool ]已经给了案例了,在读取到jar对应的class文件的时候,需要
    • 实例化
    • 属性注入的时候,可以从bean工厂中查找对应的类型set进去

      此时,jar中的实例全部持有在插件管理器中。可以缓存起来根据jar名称啥的,方便卸载的时候直接定位到。

    在业务代码中进行应用

    1. 比如你需要根据接口去获取对应的插件实现,你需要从插件管理器中先获取对象,缓存中找不到则再从bean工厂中查找。不能通过@Autowired去注入。
    // 每次获取都是手动去查找,SendService就不能通过注入的方式了。
    public void send(){
       SendService service = PluginManagerHelper.getBean(SendService.class);
       service.send();
    }
    // PluginManagerHelper的话,就遍历所有插件去找对应的类型。至于顺序是否唯一的话,根据你的实际情况写逻辑。
    

    尽量保持这个插件管理器中的所有对象不要被外面持有,否则卸载的时候就会出现无法回收的问题。

    卸载

    所有的jar对象已经被插件管理器所管理起来,卸载的话只需要从缓存中找到匹配的插件对象,删除缓存就行了,等待gc的回收。
    当业务需要再次获取SendService,遍历所有插件的时候发现那个有的插件已经不存在了,所以就匹配不到了。

    本质上还是将插件的加载作为一个子工厂来维护,不会融入到ioc容器中。这样的好处就是插件jar是有边界的。

    另外我想了一下,如果要做到和ioc融入到一起,太复杂了,容器启动的时候所有bean的周期已经确定完毕,你如果这时候要动态来一个bean,不仅要通知已经加载过的bean去看看要不要改变,而且要不断刷新容器,不过也有这样的场景,比如动态更新配置中心,但配置中心的话不会出现要卸载的情况。当然这都是 题外话了。

    以上仅为个人思路,希望能帮助到你。

    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 12月22日
  • 创建了问题 12月14日

悬赏问题

  • ¥100 求懂行的大ge给小di解答下!
  • ¥15 pcl运行在qt msvc2019环境运行效率低于visual studio 2019
  • ¥15 MAUI,Zxing扫码,华为手机没反应。可提高悬赏
  • ¥15 python运行报错 ModuleNotFoundError: No module named 'torch'
  • ¥100 华为手机私有App后台保活
  • ¥15 sqlserver中加密的密码字段查询问题
  • ¥20 有谁能看看我coe文件到底哪儿有问题吗?
  • ¥20 我的这个coe文件到底哪儿出问题了
  • ¥15 matlab使用自定义函数时一直报错输入参数过多
  • ¥15 设计一个温度闭环控制系统