構(gòu)造函數(shù)注入
publicClassOuter{
privateInnerinner;
@Autowired
publicOuter(Innerinner){
this.inner=inner;
}
}
屬性注入
publicClassOuter{
@Autowired
privateInnerinner;
}
方法注入
publicClassOuter{
privateInnerinner;
publicInnergetInner(){
returninner;
}
@Autowired
publicvoidsetInner(Innerinner){
this.inner=inner;
}
}
目前絕大部分的代碼都使用第2、第3種。第1種在bean實(shí)例化時(shí)完成,而第2、第3種的實(shí)現(xiàn)原理都是一樣的,在屬性填充時(shí)完成。本篇將介紹第二第三種的是實(shí)現(xiàn)原理
在開始之前,如果我們自己設(shè)計(jì)@Autowired
,我們應(yīng)該怎么實(shí)現(xiàn)?我想做法還是比較簡單的
- 通過反射查找bean的class下所有注解了@Autowired的字段和方法
- 獲取到字段,通過getBean(字段)獲取到對應(yīng)bean,然后再通過反射調(diào)用field的set將bean注入
@Autowired源碼分析
AutowiredAnnotationBeanPostProcessor
類
該類是@Autowired
的具體實(shí)現(xiàn)類,先預(yù)覽一下類方法
發(fā)現(xiàn)實(shí)際有機(jī)會介入bean的創(chuàng)建操作只有可能是后置處理器,用于后置處理的有3個(gè)方法,其中一個(gè)過時(shí)不用,分別是postProcessMergedBeanDefinition
、postProcessProperties
后置處理,我們再看一下這2個(gè)方法的具體代碼
publicclassAutowiredAnnotationBeanPostProcessorextendsInstantiationAwareBeanPostProcessorAdapter
implementsMergedBeanDefinitionPostProcessor,PriorityOrdered,BeanFactoryAware{
...
@Override
publicvoidpostProcessMergedBeanDefinition(RootBeanDefinitionbeanDefinition,Class>beanType,StringbeanName){
//1.尋找bean中所有被@Autowired注釋的屬性,并將屬性封裝成InjectedElement類型
InjectionMetadatametadata=findAutowiringMetadata(beanName,beanType,null);
metadata.checkConfigMembers(beanDefinition);
}
...
@Override
publicPropertyValuespostProcessProperties(PropertyValuespvs,Objectbean,StringbeanName){
//1.尋找通過@Autowired注解的屬性或者方法
InjectionMetadatametadata=findAutowiringMetadata(beanName,bean.getClass(),pvs);
try{
//2.注入
metadata.inject(bean,beanName,pvs);
}
catch(BeanCreationExceptionex){
throwex;
}
catch(Throwableex){
thrownewBeanCreationException(beanName,"Injectionofautowireddependenciesfailed",ex);
}
returnpvs;
}
...
}
跟我們的猜想是一樣的,首先先找出所有注解了@Autowired
的屬性或者方法,然后進(jìn)行注入,當(dāng)然postProcessMergedBeanDefinition
后置處理器的調(diào)用肯定是在postProcessProperties
之前的,這里我們回顧一下spring bean
的創(chuàng)建過程。
2個(gè)處理器我已用黃色標(biāo)出
1. 查找所有@Autowired
//尋找bean中所有被@Autowired注釋的屬性,并將屬性封裝成InjectedElement類型
InjectionMetadatametadata=findAutowiringMetadata(beanName,beanType,null);
privateInjectionMetadatafindAutowiringMetadata(StringbeanName,Class>clazz,@NullablePropertyValuespvs){
//Fallbacktoclassnameascachekey,forbackwardscompatibilitywithcustomcallers.
//獲取緩存的key值,一般以beanName做key
StringcacheKey=(StringUtils.hasLength(beanName)?beanName:clazz.getName());
//Quickcheckontheconcurrentmapfirst,withminimallocking.
//從緩存中獲取metadata
InjectionMetadatametadata=this.injectionMetadataCache.get(cacheKey);
//檢測metadata是否需要更新
if(InjectionMetadata.needsRefresh(metadata,clazz)){
synchronized(this.injectionMetadataCache){
metadata=this.injectionMetadataCache.get(cacheKey);
if(InjectionMetadata.needsRefresh(metadata,clazz)){
if(metadata!=null){
metadata.clear(pvs);
}
//通過clazz類,查找所有@Autowired的屬性或者方法,并封裝成InjectionMetadata類型
metadata=buildAutowiringMetadata(clazz);
//將metadata加入緩存
this.injectionMetadataCache.put(cacheKey,metadata);
}
}
}
returnmetadata;
}
可以看到spring依然在用緩存的方式提高性能,繼續(xù)跟蹤核心代碼buildAutowiringMetadata(clazz)
privateInjectionMetadatabuildAutowiringMetadata(finalClass>clazz){
//查看clazz是否有Autowired注解
if(!AnnotationUtils.isCandidateClass(clazz,this.autowiredAnnotationTypes)){
returnInjectionMetadata.EMPTY;
}
//這里需要注意AutowiredFieldElement,AutowiredMethodElement均繼承了InjectionMetadata.InjectedElement
//因此這個(gè)列表是可以保存注解的屬性和被注解的方法的
Listelements=newArrayList<>();
Class>targetClass=clazz;
//1.通過dowhile循環(huán),遞歸的往直接繼承的父類尋找@Autowired
do{
finalListcurrElements=newArrayList<>();
//2.通過反射,獲取所有屬性,doWithLocalFields則是循環(huán)的對每個(gè)屬性應(yīng)用以下匿名方法
ReflectionUtils.doWithLocalFields(targetClass,field->{
//判斷當(dāng)前field屬性是否含有@Autowired的注解
MergedAnnotation>ann=findAutowiredAnnotation(field);
if(ann!=null){
//返回該屬性在類中的修飾符,如果等于static常量,則拋出異常,@Autowired不允許注解在靜態(tài)屬性上
if(Modifier.isStatic(field.getModifiers())){
if(logger.isInfoEnabled()){
logger.info("Autowiredannotationisnotsupportedonstaticfields:"+field);
}
return;
}
//@Autowired有required屬性,獲取required的值,默認(rèn)為true
booleanrequired=determineRequiredStatus(ann);
//3.將field封裝成InjectedElement,并添加到集合中,這里用的是AutowiredFieldElement
currElements.add(newAutowiredFieldElement(field,required));
}
});
//4.@Autowired可以注解在方法上
ReflectionUtils.doWithLocalMethods(targetClass,method->{
MethodbridgedMethod=BridgeMethodResolver.findBridgedMethod(method);
if(!BridgeMethodResolver.isVisibilityBridgeMethodPair(method,bridgedMethod)){
return;
}
MergedAnnotation>ann=findAutowiredAnnotation(bridgedMethod);
if(ann!=null&&method.equals(ClassUtils.getMostSpecificMethod(method,clazz))){
if(Modifier.isStatic(method.getModifiers())){
if(logger.isInfoEnabled()){
logger.info("Autowiredannotationisnotsupportedonstaticmethods:"+method);
}
return;
}
if(method.getParameterCount()==0){
if(logger.isInfoEnabled()){
logger.info("Autowiredannotationshouldonlybeusedonmethodswithparameters:"+
method);
}
}
booleanrequired=determineRequiredStatus(ann);
PropertyDescriptorpd=BeanUtils.findPropertyForMethod(bridgedMethod,clazz);
//5.將方法封裝成InjectedElement,并添加到集合中,這里用的是AutowiredMethodElement
currElements.add(newAutowiredMethodElement(method,required,pd));
}
});
elements.addAll(0,currElements);
//返回直接繼承的父類
targetClass=targetClass.getSuperclass();
}
//如果父類不為空則需要把父類的@Autowired屬性或方法也找出
while(targetClass!=null&&targetClass!=Object.class);
//6.newInjectionMetadata(clazz,elements),將找到的所有的待注入屬性或方法生成metadata返回
returnInjectionMetadata.forElements(elements,clazz);
}
-
外層
do … while …
的循環(huán)被用于遞歸的查找父類的@Autowired
屬性或方法 -
通過反射的方式獲取到所有屬性并循環(huán)驗(yàn)證每一個(gè)屬性是否被
@Autowired
注解 -
將查找到包含
@Autowired
注解的filed封裝成AutowiredFieldElement
,加入到列表中 -
循環(huán)查找在方法上的注解
-
將找到的方法封裝成
AutowiredMethodElement
,并加入列表
這里需要特別強(qiáng)調(diào)一點(diǎn),InjectedElement
被AutowiredFieldElement
、AutowiredMethodElement
所繼承,他們都有各自的inject函數(shù),實(shí)現(xiàn)各自的注入。因此改ArrayList elements
是擁有2種類型的屬性
- 將找到的所有元素列表和clazz作為參數(shù)生成metadata數(shù)據(jù)返回
2. 注入
//注入
metadata.inject(bean,beanName,pvs);
publicvoidinject(Objecttarget,@NullableStringbeanName,@NullablePropertyValuespvs)throwsThrowable{
//獲取所有需要被注入的元素
CollectioncheckedElements=this.checkedElements;
CollectionelementsToIterate=
(checkedElements!=null?checkedElements:this.injectedElements);
//迭代的元素不為空
if(!elementsToIterate.isEmpty()){
for(InjectedElementelement:elementsToIterate){
if(logger.isTraceEnabled()){
logger.trace("Processinginjectedelementofbean'"+beanName+"':"+element);
}
//循環(huán)注入,這里有可能是AutowiredFieldElement也可能AutowiredMethodElement,因此調(diào)用的inject是2個(gè)不同的方法
element.inject(target,beanName,pvs);
}
}
}
利用for循環(huán),遍歷剛剛我們查到到的elements列表,進(jìn)行注入。
在上面有特別提醒,這里的element有可能是AutowiredFieldElement
類型、或AutowiredMethodElement
類型。各自代表@Autowired
注解在屬性上、以及注解在方法上的2種不同元素。因此他們調(diào)用的element.inject(target, beanName, pvs);
也是不一樣的
2.1 字段注入(AutowiredFieldElement)
privateclassAutowiredFieldElementextendsInjectionMetadata.InjectedElement{
@Override
protectedvoidinject(Objectbean,@NullableStringbeanName,@NullablePropertyValuespvs)throwsThrowable{
Fieldfield=(Field)this.member;
Objectvalue;
if(this.cached){
value=resolvedCachedArgument(beanName,this.cachedFieldValue);
}
else{
//專門用于注入的包裝類,包裝構(gòu)造函數(shù)參數(shù),方法參數(shù)或字段
DependencyDescriptordesc=newDependencyDescriptor(field,this.required);
//設(shè)置class
desc.setContainingClass(bean.getClass());
//需要被自動注入的beanNames,這里只有可能=1,方法注入時(shí)才有可能為多個(gè)
SetautowiredBeanNames=newLinkedHashSet<>(1);
Assert.state(beanFactory!=null,"NoBeanFactoryavailable");
TypeConvertertypeConverter=beanFactory.getTypeConverter();//獲取類型轉(zhuǎn)換器
try{
//通過beanFactory獲取屬性對應(yīng)的值,比如需要調(diào)用getBean("b")獲取依賴的屬性單例,并且通過自動轉(zhuǎn)型轉(zhuǎn)為需要的類型
value=beanFactory.resolveDependency(desc,beanName,autowiredBeanNames,typeConverter);
}
catch(BeansExceptionex){
thrownewUnsatisfiedDependencyException(null,beanName,newInjectionPoint(field),ex);
}
synchronized(this){
if(!this.cached){
if(value!=null||this.required){
this.cachedFieldValue=desc;
//注冊依賴,
registerDependentBeans(beanName,autowiredBeanNames);
//因?yàn)槭菍傩宰⑷耄虼诉@里只有可能等于1
if(autowiredBeanNames.size()==1){
StringautowiredBeanName=autowiredBeanNames.iterator().next();
if(beanFactory.containsBean(autowiredBeanName)&&
beanFactory.isTypeMatch(autowiredBeanName,field.getType())){
//緩存當(dāng)前value
this.cachedFieldValue=newShortcutDependencyDescriptor(
desc,autowiredBeanName,field.getType());
}
}
}
else{
this.cachedFieldValue=null;
}
this.cached=true;
}
}
}
if(value!=null){
//通過反射,將value值設(shè)置到bean中
ReflectionUtils.makeAccessible(field);
field.set(bean,value);
}
}
}
上方大部分的工作都在做待注入bean的獲取以及類型的轉(zhuǎn)換,如果深究下去可以再把spring Ioc講一遍,但是核心還是getBean(字段)獲取到對應(yīng)bean…我們這里就關(guān)心核心的語句,就是這2句
if(value!=null){
//通過反射,將value值設(shè)置到bean中
ReflectionUtils.makeAccessible(field);
field.set(bean,value);
}
spring通過反射的方式,調(diào)用field的set進(jìn)行屬性的注入
2.2 方法注入(AutowiredMethodElement)
privateclassAutowiredMethodElementextendsInjectionMetadata.InjectedElement{
@Override
protectedvoidinject(Objectbean,@NullableStringbeanName,@NullablePropertyValuespvs)throwsThrowable{
if(checkPropertySkipping(pvs)){
return;
}
//@Autowired標(biāo)注在方法上
Methodmethod=(Method)this.member;
Object[]arguments;
if(this.cached){
//Shortcutforavoidingsynchronization...
//有緩存
arguments=resolveCachedArguments(beanName);
}
else{
//沒緩存,直接獲取方法上所有的參數(shù)
intargumentCount=method.getParameterCount();
arguments=newObject[argumentCount];
DependencyDescriptor[]descriptors=newDependencyDescriptor[argumentCount];
SetautowiredBeans=newLinkedHashSet<>(argumentCount);
Assert.state(beanFactory!=null,"NoBeanFactoryavailable");
TypeConvertertypeConverter=beanFactory.getTypeConverter();
//循環(huán)所有參數(shù)
for(inti=0;inewMethodParameter(method,i);
DependencyDescriptorcurrDesc=newDependencyDescriptor(methodParam,this.required);
currDesc.setContainingClass(bean.getClass());
descriptors[i]=currDesc;
try{
//通過beanFactory,獲取代注入的bean,并進(jìn)行類型轉(zhuǎn)換
Objectarg=beanFactory.resolveDependency(currDesc,beanName,autowiredBeans,typeConverter);
if(arg==null&&!this.required){
arguments=null;
break;
}
arguments[i]=arg;
}
catch(BeansExceptionex){
thrownewUnsatisfiedDependencyException(null,beanName,newInjectionPoint(methodParam),ex);
}
}
synchronized(this){
if(!this.cached){
if(arguments!=null){
DependencyDescriptor[]cachedMethodArguments=Arrays.copyOf(descriptors,arguments.length);
//注冊依賴
registerDependentBeans(beanName,autowiredBeans);
//如果自動注入的個(gè)數(shù)=參數(shù)個(gè)數(shù),則緩存
if(autowiredBeans.size()==argumentCount){
Iteratorit=autowiredBeans.iterator();
Class>[]paramTypes=method.getParameterTypes();
for(inti=0;iif(beanFactory.containsBean(autowiredBeanName)&&
beanFactory.isTypeMatch(autowiredBeanName,paramTypes[i])){
//緩存
cachedMethodArguments[i]=newShortcutDependencyDescriptor(
descriptors[i],autowiredBeanName,paramTypes[i]);
}
}
}
//緩存方法
this.cachedMethodArguments=cachedMethodArguments;
}
else{
this.cachedMethodArguments=null;
}
this.cached=true;
}
}
}
if(arguments!=null){
try{
//反射調(diào)用注入方法,將獲取到的所有bean作為參數(shù)
ReflectionUtils.makeAccessible(method);
method.invoke(bean,arguments);
}
catch(InvocationTargetExceptionex){
throwex.getTargetException();
}
}
}
}
這里與屬性注入最大的區(qū)別在于,@Autowired
注解在方法上,方法可以擁有多個(gè)參數(shù),因此這里需要通過循環(huán)將一個(gè)個(gè)獲取,而獲取bean的方式于上面一樣,本質(zhì)都是通過getBean獲取。
而核心語句還是2句
//反射調(diào)用注入方法,將獲取到的所有bean作為參數(shù)
ReflectionUtils.makeAccessible(method);
method.invoke(bean,arguments);
與屬性注入不同的是,當(dāng)@Autowired
注解在方法上,例如我們注解在setter方法上,則只需要直接調(diào)用該setter方法將參數(shù)數(shù)組傳入即可以,即使用invoke觸發(fā)方法,具體屬性賦值的過程在setter方法中由用戶自行編寫
-
源碼
+關(guān)注
關(guān)注
8文章
632瀏覽量
29116 -
注解
+關(guān)注
關(guān)注
0文章
18瀏覽量
2665
原文標(biāo)題:談?wù)?@Autowired 的實(shí)現(xiàn)原理
文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論