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);
        // beanDefinitionBuilder.addPropertyValue("name",beanName);给bean设置属性
//注册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

 

SpringContextUtil的改进版,将构建bean和获取bean统一在一个类中

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;
        }
    }

    public static <T> T getBean(String name,Class<T> beanClass) {
        try {
            return applicationContext.getBean(name,beanClass);
        } catch (NoSuchBeanDefinitionException ex) {
            return null;
        }
    }

    //通过类型获取上下文中的bean
    public static Object getBean(Class<?> requiredType) {
        return applicationContext.getBean(requiredType);
    }

    public static void setBean(String beanName,Class<?> beanClass){
        //获取ApplicationContext
        ConfigurableApplicationContext applicationContext = (ConfigurableApplicationContext) SpringContextUtil.getApplicationContext();
        //通过ApplicationContext获取DefaultListableBeanFactory
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory();
        //获取BeanDefinitionBuilder
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
        beanDefinitionBuilder.addPropertyValue("name",beanName);
        //注册bean
        beanFactory.registerBeanDefinition(beanName, beanDefinitionBuilder.getRawBeanDefinition());

    }
}

 

posted @ 2021-09-10 14:12  Mars.wang  阅读(2513)  评论(0编辑  收藏  举报