spring的属性注入通过populateBean()方法实现。分为自动装配和手动装配
实例代码
package com.populate;
@Component
public class A {
@Autowired
I b;
@Autowired
List<I> m;
@Lazy
@Autowired
C c;
@PostConstruct
public void post(){
System.out.println("PostConstruct");
}
public void setXxxx(B b){
System.out.println("setXxx");
}
}
package com.populate;
@Component
public class B implements I {
}
package com.populate;
@Component
public class C implements I{
}
package com.populate;
@Component
public interface I {
}
package com.populate;
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("a");
//beanDefinition.setAutowireMode(2); //当debug分析自动注入时打开
}
}
package com;
@Configuration
@ComponentScan("com.populate")
public class AppConfig {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println(ac.getBean(A.class));
}
}
调用链过程
AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])
AbstractAutowireCapableBeanFactory#doCreateBean
AbstractAutowireCapableBeanFactory#populateBean
postProcessAfterInstantiation
第五次后置处理器调用。判断是否需要属性注入
首先对所有的bean后置处理器进行遍历。对于符合InstantiationAwareBeanPostProcessor的调用postProcessAfterInstantiation方法。默认返回true。continueWithPropertyPopulation值默认是true将不会被修改

postProcessPropertyValues
第六次后置处理器调用。对所有后置处理器进行遍历,属于InstantiationAwareBeanPostProcessor的调用postProcessPropertyValues方法。符合InstantiationAwareBeanPostProcessor类的:
1、ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor


2、CommonAnnotationBeanPostProcessor

3、AutowiredAnnotationBeanPostProcessor
4、RequiredAnnotationBeanPostProcessor

AutowiredAnnotationBeanPostProcessor
主要分析加了Autowired注解的如何进行属性填充的
postProcessPropertyValues
AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues
首先找到AutowiringMetadata,然后调用inject进行注入

findAutowiringMetadata
AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata
经过第三次后置处理器调用。已经对注入点元数据放到injectionMetadataCache集合进行了缓存,所有到这里可以直接取出三个:
1、com.populate.I com.populate.A.b
2、java.util.List com.populate.A.m
3、com.populate.C com.populate.A.c

inject A.b属性
com.populate.I com.populate.A.b
InjectionMetadata#inject
对三个注入点数据进行遍历,依次调用inject方法。首先对com.populate.A.b的b属性调用

inject
AutowiredFieldElement#inject
转换成field,组合成DependencyDescriptor依赖描述对象desc。从beanFactory获取依赖值

resolveDependency
DefaultListableBeanFactory#resolveDependency
在这里主要有两个步骤,是否加了@lazy注解用getLazyResolutionProxyIfNecessary处理,暂时先不管。先分析com.populate.I com.populate.A.b的b属性调用doResolveDependency方法

doResolveDependency
DefaultListableBeanFactory#doResolveDependency
首先判断shortcut快捷依赖是否有值,第一次为null。然后得到b属性的依赖类型com.populate.I

resolveMultipleBeans方法处理集合形式,实例代码中的java.util.List com.populate.A.m的m属性。此时分析com.populate.I com.populate.A.b的b属性调用findAutowireCandidates方法,返回结果放到matchingBeans集合

findAutowireCandidates
DefaultListableBeanFactory#findAutowireCandidates
传入参数beanName=a,requiredType=com.populate.I ,descriptor是field b(查看debug数据)。在BeanFactory根据类型requiredType查找所有符合的beanName

beanNamesForTypeIncludingAncestors
BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, Class<?>, boolean, boolean)

getBeanNamesForType
DefaultListableBeanFactory#getBeanNamesForType(Class<?>, boolean, boolean)

doGetBeanNamesForType
DefaultListableBeanFactory#doGetBeanNamesForType
遍历beanDefinitionNames

对于匹配I类型的beanName放到result集合并返回

findAutowireCandidates
DefaultListableBeanFactory#findAutowireCandidates
返回到得到candidateNames候选值。从beanFactory根据类型匹配得到的BeanName之后,首先判断resolvableDependencies集合中是否匹配当前类型I及其他的判断

遍历candidateNames候选值

根据遍历candidateNames候选值得到类型并放到candidates集合
DefaultListableBeanFactory#addCandidateEntry

getType
AbstractBeanFactory#getType
获取candidate名字的类型
得到autowiredBeanName=b,从beanFactory的singletonObjects获取b的对象返回null

从mbd获取b的类型

AbstractAutowireCapableBeanFactory#predictBeanType

AbstractAutowireCapableBeanFactory#determineTargetType

遍历candidateNames完成,并把candidateName匹配的类型放到result集合并返回
doResolveDependency
DefaultListableBeanFactory#doResolveDependency
findAutowireCandidates方法得到匹配I接口的bean的matchingBeans含有两个(就是上步返回的result集合)。如果数量大于1,进入determineAutowireCandidate方法进一步处理

determineAutowireCandidate
DefaultListableBeanFactory#determineAutowireCandidate
首先判断是否符合primary或priority

根据匹配的candidates集合的键(b和c)与加了Autowire属性名字(b)是否匹配是否相同,此时匹配b并返回

获取到instanceCandidate匹配的class类型

根据class类型从beanFactory获取对象

DependencyDescriptor#resolveCandidate
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
return beanFactory.getBean(beanName);
}
把得到的instanceCandidate赋值给result并返回,返回B对象

inject
AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
创建ShortcutDependencyDescriptor快捷依赖描述赋值给cachedFieldValue

并把cached赋值为true

通过field.set方法,注入属性值

此时便完成了加了@Autowired注解的属性b的注入。
在注入A.b属性过程中根据byType从Bean工厂获取找到了符合I接口的有两个。对于获取的candidateName从单例池获取如果返回null,则从相应的mdb中获取class类型,得到类型并封装成matchingBeans。然后再根据属性名称与符合接口的matchingBeans集合里面的值是否相匹配,最终找到一个。然后在匹配集合matchingBeans中得到类。
inject A.m属性
java.util.List com.populate.A.m
DefaultListableBeanFactory#doResolveDependency

首先通过getDependencyType得到依赖的类型list
DefaultListableBeanFactory#resolveMultipleBeans
数组isArray

Collection类型且是接口isInterface
A.m属性符合条件,并获取符合注解类型的matchingBeans。经过TypeConverter转换并放到result中并返回


Map类型

此时再经过field.set便完成了加了@Autowired注解的属性b的注入。
inject A.c属性
对于属性加了@lazy的
com.populate.C com.populate.A.c

ContextAnnotationAutowireCandidateResolver#getLazyResolutionProxyIfNecessary

ContextAnnotationAutowireCandidateResolver#buildLazyResolutionProxy

创建cglib代理并返回

此时再经过field.set便完成了加了@Autowired注解的属性c的注入。
自动装配
仅分析自动装配模型是2(AUTOWIRE_BY_TYPE)通过类型装配过程
在分析之前,首先说明一下java的内省(Introspection)机制:
内省类提供了标准方法获取目标java Bean的属性、事件、方法。BeanInfo包括BeanDescriptor、EventSetDescriptor、PropertyDescriptor、MethodDescriptor等描述
populateBean
AbstractAutowireCapableBeanFactory#populateBean
首先根据装配类型AUTOWIRE_BY_TYPE,进入autowireByType(beanName, mbd, bw, newPvs)方法。在分析autowireByType调用链之前,先看看运行之后的结果是什么。
最终结果会得到MutablePropertyValues类型的属性值:其中 name是xxxx value是B。
然后debug查看这些结果是怎么获取的

autowireByType
AbstractAutowireCapableBeanFactory#autowireByType
经过unsatisfiedNonSimpleProperties方法会得到propertyNames数组值xxxx,所以重点分析这个方法

unsatisfiedNonSimpleProperties
AbstractAutowireCapableBeanFactory#unsatisfiedNonSimpleProperties
bw.getPropertyDescriptors()方法会得到PropertyDescriptor属性描述数组,其中包含xxxx,然后对pds进行遍历,是否符合WriteMethod方法,对于符合条件的PropertyDescriptor放到result集合并返回。所以需要进入分析getPropertyDescriptors这个方法。分析如何获取到的属性描述类PropertyDescriptor

getPropertyDescriptors
BeanWrapperImpl#getPropertyDescriptors

getCachedIntrospectionResults
BeanWrapperImpl#getCachedIntrospectionResults

CachedIntrospectionResults#forClass
为给定的bean类创建CachedIntrospectionResults类

CachedIntrospectionResults#CachedIntrospectionResults

CachedIntrospectionResults#getBeanInfo(java.lang.Class<?>)
获取给定类的Beaninfo描述符

java.beans.Introspector#getBeanInfo(java.lang.Class<?>)

java.beans.Introspector#getBeanInfo()
对java bean内省,获取它的所有属性、方法和事件

java.beans.Introspector#getTargetPropertyInfo
添加superBeanInfo父类的PropertyDescriptors到pdStore集合

获取当前类的所有方法并遍历。如果方法isStatic则直接跳过

获取当前方法名、参数类型、返回类型。如果方法名长度小于3且不是以is开头的直接跳过

如果参数数量是0,方法名以get开头的。创建PropertyDescriptor对象(如getAaa,则名字是aaa)

参数个数是1,方法以set开头且返回类型是void 则创建PropertyDescriptor

参数个数是2,方法以set开头且第一个参数是Int类型,返回类型是void创建PropertyDescriptor 集合形式根据索引下标添加


最终返回到AbstractAutowireCapableBeanFactory#populateBean方法

AbstractAutowireCapableBeanFactory#applyPropertyValues


AbstractPropertyAccessor#setPropertyValues(PropertyValues)

最终调用到writeMethod.invoke()调用方法
总结:
spring bean的属性注入分为手动注入和自动注入
手动注入:通过注解,典型案例是@Autowire、@Resource
通过调用相应的bean后置处理器的postProcessPropertyValues方法,通过field.set注入
自动装配:根据自动装配模型1(byName)、2(byType)
主要使用java的内省机制获取set开头方法,method.invoke调用
网友评论