SpringBoot动态注入Bean
1、动态注入Bean示例
- 创建接口及其实现类
public interface BaseTest {
String getValue();
}
public class TestOne implements BaseTest {
@Override
public String getValue() {
return "test one";
}
}
public class TestTwo implements BaseTest {
@Override
public String getValue() {
return "test two";
}
}
- 创建Bean管理工具类
import java.util.LinkedHashMap;
import java.util.Map;
public final class TestBeanHolder {
private TestBeanHolder() {
throw new RuntimeException("无法创建工具类对象");
}
private static ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
private static Map<String, BaseTest> config = new LinkedHashMap<>();
static {
// 根据实际情况添加Bean
config.put("one", new TestOne());
config.put("two", new TestTwo());
}
public static Map<String, BaseTest> getTestBeans() {
return config;
}
public static void setKey(String key) {
threadLocal.set(key);
}
public static BaseTest getCurrentBaseTest() {
return config.get(threadLocal.get());
}
}
- 实现ObjectFactory
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;
import java.io.Serializable;
public class TestObjectFactory implements ObjectFactory<BaseTest>, Serializable {
@Override
public BaseTest getObject() throws BeansException {
return TestBeanHolder.getCurrentBaseTest();
}
}
- 注册依赖(指定类型Bean)
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
@Component
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.registerResolvableDependency(BaseTest.class, new TestObjectFactory());
}
}
2、注意事项
-
BaseTest必须是接口类型、BeanFactory必须实现Serializable接口,Spring才会通过注册的BeanFactory获取Bean。
DefaultListableBeanFactory类的findAutowireCandidates方法中,通过AutowireUtils类的resolveAutowiringValue方法查找某种类型可自动注入的Bean。 在AutowireUtils类的resolveAutowiringValue方法中,当类型是接口类型且BeanFactory实例实现了Serializable接口时,会为该类型创建代理对象。 通过代理对象调用方法时,会触发ObjectFactoryDelegatingInvocationHandler的invoke方法。其中,会通过注册的BeanFactory实例获取实际的对象。
-
无法在BeanFactoryPostProcessor中注入普通Bean。
在AbstractApplicationContext类中的refresh方法中,有如下代码段。其中BeanFactoryPostProcessor在其它非懒加载Bean创建之前执行。因此,在BeanFactoryPostProcessor中,无法注入非懒加载的Bean。
3、本文中动态注入Bean方法的优缺点
- 优点
- 在需要使用的地方,可直接通过@Resource等方式注入。
- 间接实现了Bean的懒加载:在使用的时候获取。
- 缺点
- 所需的Bean必须是接口类型,不适合现有类的改造。
- 所需的Bean需要自己维护。