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