有時候我們需要在項目中動態加載或者卸載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"; }
參考: