使用spring往一个bean(BeanB)注入另一个bean(BeanA),发现BeanA为null,注入失败了。
/**
* @author huangd
* @date 2021-11-30
**/
@Component
public class BBean {
@Autowired
private ABean aBean;
public BBean() {
System.out.println("BBean instantiation start...");
}
public ABean getABean() {
return aBean;
}
}
@Component
public class ABean {
private String name = "nameA";
public ABean() {
System.out.println("ABean instantiation start...");
}
public String getName() {
return name;
}
}
@Component
public class MyGetBeanFactory implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BBean bean = beanFactory.getBean(BBean.class);
System.out.println("BBean依赖注入ABean is " + bean.getABean());
}
}
上面代码比较简单,自定义一个BeanFactoryPostProcessor,并且在postProcessBeanFactory方法里面显示调用beanFactory.getBean(BBean.class);
我们都知道这个getBean方法会去实例化和初始化bean,spring都是这样去创建bean的。
接下来启动应用
发现BBean注入ABean为null,注入失效了。
首先要知道依赖注入是通过BeanPostProcessor来完成的,主要是以下这哥俩:
AutowiredAnnotationBeanPostProcessor (@Autowired)
CommonAnnotationBeanPostProcessor (@Resource)
我们再看org.springframework.context.support.AbstractApplicationContext#refresh方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
throw ex;
}
finally {singleton beans anymore...
resetCommonCaches();
}
}
}
上面我自定义实现了BeanFactoryPostProcessor接口的MyGetBeanFactory类,它postProcessBeanFactory的方法被执行,就是由invokeBeanFactoryPostProcessors(beanFactory)这句话来发起的,而将BeanPostProcessor注册到spring中,却是由下面这句registerBeanPostProcessors(beanFactory)完成。
看到这里,我想你应该明白了吧,因为我们在方法postProcessBeanFactory中调getBean(BBean.class)时,BeanPostProcessor还没实例化呢,也就是说还没放到spring中,所以肯定不会完成注入啊,因为AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor这哥俩还没添加到
org.springframework.beans.factory.support.AbstractBeanFactory#beanPostProcessors集合中。
我们看下实现注入属性的代码位置:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
有一段:
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
从getBeanPostProcessors()中拿BeanPostProcessor,遍历去拿上面那哥俩来完成注入,但是这时候还没有啊,所以无法注入。
再看回
org.springframework.context.support.AbstractApplicationContext#refresh中registerBeanPostProcessors这句,它的工作就是注入BeanPostProcessor。
好了,所以要想能够注入正确,就必须先有BeanPostProcessor,我们不能在BeanFactoryPostProcessor里面去创建bean,因为这时候还没BeanPostProcessor,spring也不建议我们在BeanFactoryPostProcessor中去创建bean,以免出现副作用。