Spring依赖注入Bean为空,注入失效场景

场景介绍

使用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的。

接下来启动应用
Spring依赖注入Bean为空,注入失效场景_第1张图片
发现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中,所以肯定不会完成注入啊,因为AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor这哥俩还没添加到
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,以免出现副作用。

你可能感兴趣的:(spring,spring,java,后端)