spring

spring属性注入

2019-11-29  本文已影响0人  love111

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将不会被修改


populateBean5.png

postProcessPropertyValues

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


populateBean.png
ImportAwareBeanPostProcessor.png

2、CommonAnnotationBeanPostProcessor


findResourceMetadata.png
3、AutowiredAnnotationBeanPostProcessor
4、RequiredAnnotationBeanPostProcessor
RequiredAnnotationBPP.png

AutowiredAnnotationBeanPostProcessor

主要分析加了Autowired注解的如何进行属性填充的

postProcessPropertyValues

AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues
首先找到AutowiringMetadata,然后调用inject进行注入


postProcessPropertyValues.png
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


findAutowiringMetadata.png

inject A.b属性

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


inject-Ab.png
inject

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


injectFieldElement.png
resolveDependency

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


resolveDependency.png
doResolveDependency

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


doResolveDependency.png

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


doResolveDependency2.png
findAutowireCandidates

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


findAutowireCandidates.png
beanNamesForTypeIncludingAncestors

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


beanNamesForTypeIncludingAncestors.png
getBeanNamesForType

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


getBeanNamesForType.png
doGetBeanNamesForType

DefaultListableBeanFactory#doGetBeanNamesForType
遍历beanDefinitionNames


doGetBeanNamesForType.png

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


doGetBeanNamesForType2.png
findAutowireCandidates

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


findAutowireCandidates2.png

遍历candidateNames候选值


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

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


getType2.png

从mbd获取b的类型


predictBeanType.png
AbstractAutowireCapableBeanFactory#predictBeanType
predictBeanType2.png
AbstractAutowireCapableBeanFactory#determineTargetType
determineTargetType.png

遍历candidateNames完成,并把candidateName匹配的类型放到result集合并返回

doResolveDependency

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


matchingBeans.png

determineAutowireCandidate

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


determineAutowireCandidate1.png

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


determineAutowireCandidate2.png
获取到instanceCandidate匹配的class类型
instanceCandidate.png
根据class类型从beanFactory获取对象
instanceCandidate2.png

DependencyDescriptor#resolveCandidate

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
            throws BeansException {
        return beanFactory.getBean(beanName);
    }

把得到的instanceCandidate赋值给result并返回,返回B对象


instanceCandidate3.png
inject

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


shortcutDD.png

并把cached赋值为true


AutowiredFieldElementinject.png
通过field.set方法,注入属性值
Fieldset.png
此时便完成了加了@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


doResolveDependencymulti.png

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


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

Map类型


resolveMultipleBeans4.png
此时再经过field.set便完成了加了@Autowired注解的属性b的注入。

inject A.c属性

对于属性加了@lazy的
com.populate.C com.populate.A.c


getLazyResolutionProxy.png

ContextAnnotationAutowireCandidateResolver#getLazyResolutionProxyIfNecessary


getLazyResolutionProxyIfNecessary.png
ContextAnnotationAutowireCandidateResolver#buildLazyResolutionProxy
buildLazyResolutionProxy1.png
创建cglib代理并返回
buildLazyResolutionProxy3.png

此时再经过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查看这些结果是怎么获取的


populateautowireByType.png
autowireByType

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


autowireByType.png
unsatisfiedNonSimpleProperties

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


unsatisfiedNonSimpleProperties.png
getPropertyDescriptors

BeanWrapperImpl#getPropertyDescriptors


getPropertyDescriptors.png
getCachedIntrospectionResults

BeanWrapperImpl#getCachedIntrospectionResults


getCachedIntrospectionResults.png

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


forclass.png
CachedIntrospectionResults#CachedIntrospectionResults
CachedIntrospectionResults.png

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


getBeanInfo.png
java.beans.Introspector#getBeanInfo(java.lang.Class<?>)
getBeanInfoIntrospector.png
java.beans.Introspector#getBeanInfo()
对java bean内省,获取它的所有属性、方法和事件
getBeanInfoPD.png
java.beans.Introspector#getTargetPropertyInfo
添加superBeanInfo父类的PropertyDescriptors到pdStore集合
getTargetPropertyInfo1.png

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


getTargetPropertyInfo2.png
获取当前方法名、参数类型、返回类型。如果方法名长度小于3且不是以is开头的直接跳过
getTargetPropertyInfo3.png
如果参数数量是0,方法名以get开头的。创建PropertyDescriptor对象(如getAaa,则名字是aaa)
getTargetPropertyInfo4.png
参数个数是1,方法以set开头且返回类型是void 则创建PropertyDescriptor
getTargetPropertyInfo5.png
参数个数是2,方法以set开头且第一个参数是Int类型,返回类型是void创建PropertyDescriptor 集合形式根据索引下标添加
PropertyDescriptor6.png
getTargetPropertyInfo6.png
最终返回到AbstractAutowireCapableBeanFactory#populateBean方法
populateBean3.png
AbstractAutowireCapableBeanFactory#applyPropertyValues
applyPropertyValues.png
MutablePropertyValues.png
AbstractPropertyAccessor#setPropertyValues(PropertyValues)
setPropertyValues.png
最终调用到writeMethod.invoke()调用方法

总结:

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

上一篇 下一篇

猜你喜欢

热点阅读