• 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

  • 相关阅读:
    Linux内核info leak漏洞
    ELK Stack部署
    centos下安装opencv
    windows10 进入BIOS
    Dockerfile语法简介
    JAVA 容器配置 JVM 监控
    docker registry
    squid
    正反向代理
    安装plsql
  • 原文地址:https://www.cnblogs.com/wangbin2188/p/15251103.html
Copyright © 2020-2023  润新知