【Spring】深入解析 bean 的属性填充 一 autowireByName autowireByType
前言
@Configuration
public class Config {
@Bean
public BasicPOJO a() {
return new BasicPOJO("a");
}
@Bean
public BasicPOJO b() {
return new BasicPOJO("b");
}
@Bean
public GenericPOJO<Integer, Integer> integerGenericPOJO() {
return new GenericPOJO<Integer, Integer>("integer");
}
@Bean
public GenericPOJO<String, String> stringGenericPOJO() {
return new GenericPOJO<String, String>("string");
}
@Component
public class Container {
// 注入上述实例 a
@Autowired
BasicPOJO a;
// 基于 Value 注解解析 SpEL 表达式,也可以注入 bean实例
@Value("#{a}")
BasicPOJO aValue;
// 基于 Qualifier 注解解析注入实例 b
@Autowired
@Qualifier("b")
BasicPOJO basicPOJO;
// Qualifier 作为元注解解析注入实例 b
@Autowired
@MyQualifier("b")
BasicPOJO basicPOJO2;
// 以 name -> 实例 形式注入所有 BasicPOJO 实例
@Autowired
Map<String, BasicPOJO> map;
// 注入指定泛型实例
@Autowired
GenericPOJO<Integer, Integer> i;
GenericPOJO<String, String> s;
// 基于方法注入指定泛型实例
@Autowired
public void setStringGenericPOJO(GenericPOJO<String, String> stringGenericPOJO) {
this.s = stringGenericPOJO;
}
}
}
如上配置类,组件 Container
的所有属性是可以被完整填充的,这就是我们所谓的 IOC
,bean实例
的属性填充通常发生在实例化 Instantiation
完成后(除非是指定了 AUTOWIRE_CONSTRUCTOR
或者 @Bean
注册的实例),本文分多个章节了解如下相关:
- 属性填充的时机及上下文
byName
byType
自动依赖注入- 核心:基于
@Autowired
注解的属性填充,主要解读AutowiredAnnotationBeanPostProcessor
类相关,其中涉及的诸多细节,比如上述实例的属性如何符合我们预期被注入
AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
/**
* 构造(或从缓存获取)对应 bean实例 的 BeanWrapper
*/
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
/**
* 实例创建完成后,调用所有
* MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
* 对目标 bean实例 的 BeanDefinition 进行后处理
* 在这个过程中,AutowiredAnnotationBeanPostProcessor 会把
* 所有需要注入的元素(属性、方法)收集起来
*/
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
}
mbd.postProcessed = true;
}
}
// 对于 循环依赖 的单例此处现提前暴露实例给单例工厂(二级缓存)
// ...
Object exposedObject = bean;
try {
// 属性填充
populateBean(beanName, mbd, instanceWrapper);
// 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
}
// ...
return exposedObject;
}
基于容器中的 BeanDefinition
创建 bean实例
时,最终委托给方法 AbstractAutowireCapableBeanFactory#doCreateBean
,主要流程如下:
- 基于
createBeanInstance
方法创建对应的BeanWrapper
,该过程中对于指定了依赖注入模式为构造方法注入(AUTOWIRE_CONSTRUCTOR)
或通过工厂方法(比如基于@Bean
注册)创建的实例会以构造方法自动依赖注入
的形式进行一次属性填充,此处不做深入了解 - 执行所有
MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
,其中AutowiredAnnotationBeanPostProcessor
会收集所有需要进行注入的元素,即所有被@Autowired
@Value
注解的属性与方法 - 基于
populateBean
方法进行属性填充 initializeBean
方法执行初始化相关
上述诸多细节在之前的 BeanFactory
相关文章都有解读,可前往对应专栏参考,本文重点关注 populateBean
populateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// ...
/**
* 此处是调用所有的 InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
* 但凡有返回 false,此处就 return 不继续注入了,目前的默认实现都是 true
*/
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
// 从 BeanDefinition 获取 PropertyValues
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
/**
* 自动注入模式
* AUTOWIRE_BY_NAME:根据名称注入
* AUTOWIRE_BY_TYPE:根据类型注入
* 一般情况 resolvedAutowireMode == AUTOWIRE_NO
*/
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
/**
* 如果存在 InstantiationAwareBeanPostProcessor
* 则执行所有 InstantiationAwareBeanPostProcessor#postProcessProperties
* 辅助完成属性填充,诸如基于 @Autowired 等注解的属性注入就发生在此处
*/
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
// 依赖校验...
// 属性绑定
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
属性填充的核心方法,主要流程如下:
- 在进行属性填充之前,执行所有
InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
方法,此处如果有返回false
,则不再进行下去,目前所有的实现都是返回true
- 基于
BeanDefinition
获取PropertyValues
,用于后续基于BeanWrapper
进行属性赋值 - 基于
AutowireMode
进行byName
byType
依赖自动注入,下文会再解读 - 执行所有
InstantiationAwareBeanPostProcessor#postProcessProperties
,其中本文重点关注的是AutowiredAnnotationBeanPostProcessor
:基于@Autowired
@Value
注解的属性注入,下文会再解读 applyPropertyValues
方法是基于BeanDefinition.propertyValues
的属性赋值,比如我们自行指定或基于xml
驱动时的<property>
标签指定
autowireByName
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
/**
* 收集所有需要注入的属性名称
*/
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
// 对应的属性从容器取出后放到 pvs 中
Object bean = getBean(propertyName);
pvs.add(propertyName, bean);
registerDependentBean(propertyName, beanName);
// ...
}
else {
// ...
}
}
}
byName
的属性注入:
- 收集需要自动注入的依赖属性
byName
注入的逻辑基于方法getBean(name)
autowireByType
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// ...
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
// 收集所有需要填充的 propertyName
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
if (Object.class != pd.getPropertyType()) {
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
// 构造对应的 DependencyDescriptor
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// 基于 resolveDependency 方法从容器中获取对应 bean
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
pvs.add(propertyName, autowiredArgument);
}
// 注册依赖关系
for (String autowiredBeanName : autowiredBeanNames) {
registerDependentBean(autowiredBeanName, beanName);
}
autowiredBeanNames.clear();
}
}
catch (BeansException ex) {
}
}
}
byType
的属性注入:
- 整体思路与
byName
注入差不多,区别在于此处基于resolveDependency
方法获取对应bean
resolveDependency
是解析注入的核心方法,由AutowireCapableBeanFactory
接口定义,最终实现在DefaultListableBeanFactory
中,下文中AutowiredAnnotationBeanPostProcessor
也会用到此方法,到时会详细分析该方法
一般的,我们并不会特别的指定对应 bean
实例为 byName
byType
诸如,即默认情况下都是基于注解进行属性注入,接下来重点解读基于后处理器的属性注入,比如 AutowiredAnnotationBeanPostProcessor
AutowiredAnnotationBeanPostProcessor#postProcessProperties
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
/**
* 获取所有待注入的元素:
* 这些元素是在 postProcessMergedBeanDefinition 阶段被收集起来的
*/
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
/**
* 进行元素注入
*/
try {
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
}
return pvs;
}
-------------- InjectionMetadata#inject ---------------
/**
* 执行所有 InjectedElement#inject
* 属性:AutowiredFieldElement
* 方法:AutowiredMethodElement
*/
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
element.inject(target, beanName, pvs);
}
}
}
- 在
postProcessMergedBeanDefinition
阶段(发生在bean实例对象
刚被创建完后),AutowiredAnnotationBeanPostProcessor
会收集所有需要被注入的属性和方法(被@Autowired
@Value
注解修饰) - 对应属性被封装成
AutowiredFieldElement
,对应方法被封装成AutowiredMethodElement
- 在该阶段,会执行上述元素的
inject
方法进行注入,后续我们会重点解读InjectedElement#inject
方法 postProcessPropertyValues
方法已被标注@Deprecated
,在后续版本会移除,此处只是做了兜底
总结
本章节,我们对整个属性注入的链路做了梳理,同时解读了 byName
byType
属性填充的原理,其中 byType
注入委托的核心方法 resolveDependency
我们会在下章重点解读
之后在 postProcessProperties
阶段的属性注入是本文的核心,核心逻辑收口到 InjectedElement#inject
,其中涉及的细节也很多,会在下章详细解读
参考
【小家Spring】细说Spring IOC容器的自动装配(@Autowired),以及Spring4.0新特性之【泛型依赖注入】的源码级解析