有时候我们需要在项目中动态加载或者卸载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";
}