Spring Boot 手动将实例添加到IOC

添加实例进IOC

我们可以通过多种途径获取到:GenericApplicationContext 对象,可以使用该对象手动添加Bean进IOC容器,添加的方式有:

1
2
3
4
5
6
registerBean(Class<T>, Object...)
registerBean(String, Class<T>, Object...)
registerBean(Class<T>, BeanDefinitionCustomizer...)
registerBean(String, Class<T>, BeanDefinitionCustomizer...)
registerBean(Class<T>, Supplier<T>, BeanDefinitionCustomizer...)
registerBean(String, Class<T>, Supplier<T>, BeanDefinitionCustomizer...)

测试类

1
2
3
4
5
6
7
8
9
10
11
public class MyBean {
@Resource
private Environment env;
@PostConstruct
public void init() {
System.out.println("MyBean init");
}
public void printName() {
System.out.println(env.getProperty("spring.application.name"));
}
}

如果单纯调用registerBean添加到IOC中,@PostConstruct 和 @Resource等自动装配是不会立马执行的,只有当第一次调用 applicationContext.getBean 才会执行自动装配。

我遇到的坑

我使用了自己 registerBean(String, Class<T>, Supplier<T>, BeanDefinitionCustomizer...) 的方式添加,这里有 Supplier 需要自己 new 出实例,我立马使用导致env为空。

1
2
3
MyBean myBean = new MyBean();
applicationContext.registerBean("myBean", MyBean.class, () -> myBean);
myBean.doSomething(); // env is null

正确做法是调用一次getBean让其自动装载。

1
2
3
MyBean myBean = new MyBean();
applicationContext.registerBean("myBean", MyBean.class, () -> myBean);
applicationContext.getBean(MyBean.class).doSomething(); // env not null

也可以这通过 GenericApplicationContext.getAutowireCapableBeanFactory() 获取 AutowireCapableBeanFactory 对象,通过它创建的Bean会调用 @PostConstruct 和 @Resource等自动装配,不过要注意,此时并未添加到IOC容器,只是创建了Bean实例对象,临时使用这样就可以

1
2
MyBean myBean = applicationContext.getAutowireCapableBeanFactory().createBean(MyBean.class);
myBean.printName(); // env not null

如果要加入到IOC容器,还是要调用 registerBean

1
2
3
MyBean myBean = applicationContext.getAutowireCapableBeanFactory().createBean(MyBean.class);
myBean.printName(); // env not null
applicationContext.registerBean("myBean", MyBean.class, () -> myBean);