zoukankan      html  css  js  c++  java
  • Springboot动态装载卸载Bean

    有时候我们需要在项目中动态加载或者卸载Bean,这就需要Bean的class文件事先是存在的,只是在需要的时候才加载进来。

    比如我定义一个接口OneService和它的一个实现类,下面是比较常规的实现,调用OneService的时候,调的就是OneServiceImplA

    public interface OneService {
        String say();
    }
    
    
    
    //--------------------------------------------------
    @Service
    public class OneServiceImplA implements OneService {
        @Override
        public String say() {
            System.out.println("I'm OneServiceImplA");
            return "OneServiceImplA";
        }
    }

    但有些情况下,OneServiceImplA不能满足我的需求,我想用OneServiceImplB,可以发现这个类上没有注解,springboot启动的时候不会加载它

    public class OneServiceImplB implements OneService, InitializingBean {
        @Override
        public String say() {
            System.out.println("I'm OneServiceImplB");
            return "OneServiceImplB";
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("我是动态注册的你,不是容器启动的时候注册的你");
        }
    
        @PreDestroy
        public void preDestroy() {
            System.out.println("我被动态删除了!");
        }
    }

    当我想在项目中调用OneServiceImplB的时候怎么办?我们需要实现一个工具类

    public class SpringContextUtil {
        private static ApplicationContext applicationContext;
    
        public static ApplicationContext getApplicationContext() {
            return applicationContext;
        }
    
        public static void setApplicationContext(ApplicationContext applicationContext) {
            SpringContextUtil.applicationContext = applicationContext;
        }
    
        //通过名字获取上下文中的bean
        public static Object getBean(String name) {
            try {
                return applicationContext.getBean(name);
            } catch (NoSuchBeanDefinitionException ex) {
                return null;
            }
        }
    
        //通过类型获取上下文中的bean
        public static Object getBean(Class<?> requiredType) {
            return applicationContext.getBean(requiredType);
        }
    }

    在项目启动的时候,把ApplicationContext对象注入进去。

    启动类:

    @SpringBootApplication
    public class ServerApplication {
        public static void main(String[] args) {
            ConfigurableApplicationContext applicationContext = SpringApplication.run(ServerApplication.class, args);
            SpringContextUtil.setApplicationContext(applicationContext);
        }
    }

    这样在有需要的时候,我们就可以动态的加载和删除这个bean了。

     /**
         * 动态注册Bean
         *
         * @param beanName
         * @return
         */
        @GetMapping("dynamicInit")
        public String initBean(String beanName) {
            //获取ApplicationContext
            ConfigurableApplicationContext applicationContext = (ConfigurableApplicationContext) SpringContextUtil.getApplicationContext();
            //通过ApplicationContext获取DefaultListableBeanFactory
            DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory();
            //获取BeanDefinitionBuilder
            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(OneServiceImplB.class);
            //注册bean
            beanFactory.registerBeanDefinition(beanName, beanDefinitionBuilder.getRawBeanDefinition());
            OneServiceImplB oneServiceImplB = (OneServiceImplB) SpringContextUtil.getBean(beanName);
            return oneServiceImplB.say();
        }
    
        /**
         * 根据beanName删除bean
         * @param beanName
         * @return
         */
        @GetMapping("dynamicRemove")
        public String removeBean(String beanName) {
            ConfigurableApplicationContext applicationContext = (ConfigurableApplicationContext) SpringContextUtil.getApplicationContext();
            DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory();
            //动态删除bean
            beanFactory.removeBeanDefinition(beanName);
            return "remove ok";
        }

     参考:

    https://www.cnblogs.com/eternityz/p/12241143.html

    https://www.jianshu.com/p/fd357e1c579e

  • 相关阅读:
    Vue 封装axios(四种请求)及相关介绍
    简单的按钮样式,两个连在一起的按钮
    http接口访问正常,https访问报错,基础连接已经关闭: 发送时发生错误.
    单点登录思路,多台服务器共用一个数据库,登录信息解决方案
    Wait()在过滤器中卡住 ,在异步代码上阻塞时的常见死锁问题
    接口对接,接口通过原有代码无法访问,解决办法,用postman解决
    svg基础标签说明
    server 2016部署网络负载平衡(NLB)
    写 JS 逻辑判断,不要只知道用 if-else 和 switch
    .NetCore部署IIS出错原因未安装ASP.N.NetCore部署IIS出错原因未安装ASP.NET Core Module v2ET Core Module v2
  • 原文地址:https://www.cnblogs.com/wangbin2188/p/15251103.html
Copyright © 2011-2022 走看看