您现在的位置是:首页 >学无止境 >动态加载外部springboot Jar网站首页学无止境

动态加载外部springboot Jar

加班狂魔 2024-06-17 10:43:13
简介动态加载外部springboot Jar

背景及实现思路

想要设计一个stater,可以方便加载一个可以完整运行的springboot单体jar包,为了在已执行的服务上面快速的扩展功能而不需要重启整个服务,又或者低代码平台生成代码之后可以快速预览。

加载jar的技术栈

  • springboot 2.2.6.RELEASE
  • mybatis-plus 3.4.1

实现加载

想要完成类加载要熟悉spring中类加载机制,以及java中classloader的双亲委派机制。

通常bean注册过程

想要实现热加载,一定得了解在spring中类的加载机制,大体上spring在扫描到@Component注解的类时,会根据其class生成对应的BeanDefinition,然后在将其注册在BeanDefinitionRegistry(这是个接口,最终由DefaultListableBeanFactory实现)。当其备引用注入实例时即getBean时被实例化并被注册到DefaultSingletonBeanRegistry中。后续单例都将由DefaultSingletonBeanRegistry所管理。

controller加载

controller的加载机制

controller所特殊的是,spring会将其注册到RequestMappingHandlerMapping中。所以想要热加载controller 就需要三步。

  1. 生成并注册BeanDefinition
  2. 生成并注册实例
  3. 注册RequestMappingHandlerMapping

代码如下

		// 获取bean工厂并转换为DefaultListableBeanFactory
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) ((ConfigurableApplicationContext)
                applicationContext).getBeanFactory();
        // 定义BeanDefinition
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
        GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionBuilder.getRawBeanDefinition();

        //设置当前bean定义对象是单利的
        beanDefinition.setScope("singleton");

        // 将变量首字母置小写
        beanName = StringUtils.uncapitalize(beanName);
        // 将构建的BeanDefinition交由Spring管理
        beanFactory.registerBeanDefinition(beanName, beanDefinition);
        // 手动构建实例,并注入base service 防止卸载之后不再生成
        Object obj = clazz.newInstance();
        beanFactory.registerSingleton(beanName, obj);
        log.info("register Singleton :" + beanName);

        final RequestMappingHandlerMapping requestMappingHandlerMapping =
                    applicationContext.getBean(RequestMappingHandlerMapping.class);

        if (requestMappingHandlerMapping != null) {
                String handler = beanName;
                Object controller = null;
                try {
                    controller = applicationContext.getBean(handler);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                if (controller == null) {
                    return beanName;
                }
                // 注册Controller
                Method method = requestMappingHandlerMapping.getClass().getSuperclass().getSuperclass().
                        getDeclaredMethod("detectHandlerMethods", Object.class);
                // 将private改为可使用
                method.setAccessible(true);
                method.invoke(requestMappingHandlerMapping, handler);
        }

controller特殊处理机制

service加载

mapper加载

其他类记载

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。