详解Java Spring各种依赖注入注解的区别
注解注入顾名思义就是通过注解来实现注入,Spring和注入相关的常见注解有Autowired、Resource、Qualifier、Service、Controller、Repository、Component。
Autowired是自动注入,自动从spring的上下文找到合适的bean来注入
Resource用来指定名称注入
Qualifier和Autowired配合使用,指定bean的名称
Service,Controller,Repository分别标记类是Service层类,Controller层类,数据存储层的类,spring扫描注解配置时,会标记这些类要生成bean。
Component是一种泛指,标记类是组件,spring扫描注解配置时,会标记这些类要生成bean。
Spring对于Bean的依赖注入,支持多种注解方式:
@Resource javax.annotation JSR250(CommonAnnotationsforJava) @Inject javax.inject JSR330(DependencyInjectionforJava) @Autowired org.springframework.bean.factory Spring
直观上看起来,@Autowired是Spring提供的注解,其他几个都是JDK本身内建的注解,Spring对这些注解也进行了支持。但是使用起来这三者到底有什么区别呢?笔者经过方法的测试,发现一些有意思的特性。
区别总结如下:
一、@Autowired有个required属性,可以配置为false,这种情况下如果没有找到对应的bean是不会抛异常的。@Inject和@Resource没有提供对应的配置,所以必须找到否则会抛异常。
二、@Autowired和@Inject基本是一样的,因为两者都是使用AutowiredAnnotationBeanPostProcessor来处理依赖注入。但是@Resource是个例外,它使用的是CommonAnnotationBeanPostProcessor来处理依赖注入。当然,两者都是BeanPostProcessor。
@Autowired和@Inject -默认autowiredbytype -可以通过@Qualifier显式指定autowiredbyqualifiername。 -如果autowiredbytype失败(找不到或者找到多个实现),则退化为autowiredbyfieldname @Resource -默认autowiredbyfieldname -如果autowiredbyfieldname失败,会退化为autowiredbytype -可以通过@Qualifier显式指定autowiredbyqualifiername -如果autowiredbyqualifiername失败,会退化为autowiredbyfieldname。但是这时候如果autowiredbyfieldname失败,就不会再退化为autowiredbytype了。
TIPSQualifiednameVSBeanname
在Spring设计中,Qualifiedname并不等同于Beanname,后者必须是唯一的,但是前者类似于tag或者group的作用,对特定的bean进行分类。可以达到getByTag(group)的效果。对于XML配置的bean,可以通过id属性指定beanname(如果没有指定,默认使用类名首字母小写),通过标签指定qualifiername:
<beanid="lamborghini"class="me.arganzheng.study.spring.autowired.Lamborghini"> <qualifiervalue="luxury"/> <!--injectanydependenciesrequiredbythisbean--> </bean>
如果是通过注解方式,那么可以通过@Qualifier注解指定qualifiername,通过@Named或者@Component(@Service,@Repository等)的value值指定beanname:
@Component("lamborghini")
@Qualifier("luxury")
publicclassLamborghiniimplementsCar{
}
或者
@Component
@Named("lamborghini")
@Qualifier("luxury")
publicclassLamborghiniimplementsCar{
}
同样,如果没有指定beanname,那么Spring会默认是用类名首字母小写(Lamborghini=>lamborghini)。
三、通过Anotation注入依赖的方式在XML注入方式之前进行。如果对同一个bean的依赖同时使用了两种注入方式,那么XML的优先。但是不同担心通过Anotation注入的依赖没法注入XML中配置的bean,依赖注入是在bean的注册之后进行的。
四、目前的autowiredbytype方式(笔者用的是3.2.3.RELEASE版本),Spring的AutowiredAnnotationBeanPostProcessor实现都是有”bug”的,也就是说@Autowired和@Inject都是有坑的(称之为坑,不称之为bug是因为貌似是故意的。。)。这是来源于线上的一个bug,也是这边文章的写作原因。现场如下:
application-context.xml中有如下定义:
<xmlversion="1.0"encoding="UTF-8"?> <beansxmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-2.5.xsd"> <context:annotation-config/> <context:component-scanbase-package="me.arganzheng.study"/> <util:constantid="en" static-field="me.arganzheng.study.spring.autowired.Constants.Language.EN"/> <util:constantid="ja" static-field="me.arganzheng.study.spring.autowired.Constants.Language.JP"/> <util:constantid="ind" static-field="me.arganzheng.study.spring.autowired.Constants.Language.IND"/> <util:constantid="pt" static-field="me.arganzheng.study.spring.autowired.Constants.Language.PT"/> <util:constantid="th" static-field="me.arganzheng.study.spring.autowired.Constants.Language.TH"/> <util:constantid="ar" static-field="me.arganzheng.study.spring.autowired.Constants.Language.AR"/> <util:constantid="en-rIn" static-field="me.arganzheng.study.spring.autowired.Constants.Language.EN_RIN"/> <util:mapid="languageChangesMap"key-type="java.lang.String" value-type="java.lang.String"> <entrykey="pt"value="pt"/> <entrykey="br"value="pt"/> <entrykey="jp"value="ja"/> <entrykey="ja"value="ja"/> <entrykey="ind"value="ind"/> <entrykey="id"value="ind"/> <entrykey="en-rin"value="en-rIn"/> <entrykey="in"value="en-rIn"/> <entrykey="en"value="en"/> <entrykey="gb"value="en"/> <entrykey="th"value="th"/> <entrykey="ar"value="ar"/> <entrykey="eg"value="ar"/> </util:map> </beans>
其中static-field应用的常量定义在如下类中:
packageme.arganzheng.study.spring.autowired;
publicinterfaceConstants{
publicinterfaceLanguage{
publicstaticfinalStringEN="CommonConstants.LANG_ENGLISH";
publicstaticfinalStringJP="CommonConstants.LANG_JAPANESE";
publicstaticfinalStringIND="CommonConstants.LANG_INDONESIAN";
publicstaticfinalStringPT="CommonConstants.LANG_PORTUGUESE";
publicstaticfinalStringTH="CommonConstants.LANG_THAI";
publicstaticfinalStringEN_RIN="CommonConstants.LANG_ENGLISH_INDIA";
publicstaticfinalStringAR="CommonConstants.LANG_Arabic";
}
}
然后如果我们在代码中如下声明依赖:
publicclassAutowiredTestextendsBaseSpringTestCase{
@Autowired
privateMap<String,String>languageChangesMap;
@Test
publicvoidtestAutowired(){
notNull(languageChangesMap);
System.out.println(languageChangesMap.getClass().getSimpleName());
System.out.println(languageChangesMap);
}
}
Guesswhat,诡异的事情发生了!
运行结果如下:
LinkedHashMap
{en=CommonConstants.LANG_ENGLISH,ja=CommonConstants.LANG_JAPANESE,ind=CommonConstants.LANG_INDONESIAN,pt=CommonConstants.LANG_PORTUGUESE,th=CommonConstants.LANG_THAI,ar=CommonConstants.LANG_Arabic,en-rIn=CommonConstants.LANG_ENGLISH_INDIA}
也就是说Map
严重:CaughtexceptionwhileallowingTestExecutionListener
[org.springframework.test.context.support.DependencyInjectionTestExecutionListener@5c51ee0a]topreparetestinstance[me.arganzheng.study.spring.autowired.AutowiredTest@6e301e0]
org.springframework.beans.factory.BeanCreationException:Errorcreatingbeanwithname'me.arganzheng.study.spring.autowired.AutowiredTest':Injectionofautowireddependenciesfailed;nestedexceptionisorg.springframework.beans.factory.BeanCreationException:Couldnotautowirefield:privatejava.util.Mapme.arganzheng.study.spring.autowired.AutowiredTest.languageChangesMap;nestedexceptionisorg.springframework.beans.factory.NoSuchBeanDefinitionException:Noqualifyingbeanoftype[java.lang.String]foundfordependency[mapwithvaluetypejava.lang.String]:expectedatleast1beanwhichqualifiesasautowirecandidateforthisdependency.Dependencyannotations:{@org.springframework.beans.factory.annotation.Autowired(required=true)}
...
edby:org.springframework.beans.factory.NoSuchBeanDefinitionException:Noqualifyingbeanoftype[java.lang.String]foundfordependency[mapwithvaluetypejava.lang.String]:expectedatleast1beanwhichqualifiesasautowirecandidateforthisdependency.Dependencyannotations:{@org.springframework.beans.factory.annotation.Autowired(required=true)}
atorg.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
atorg.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843)
atorg.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
atorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
...28more
debug了一下,发现确实是Spring的一个bug。在DefaultListableBeanFactory的这个方法出问题了:
protectedObjectdoResolveDependency(DependencyDescriptordescriptor,Class<?>type,StringbeanName,
Set<String>autowiredBeanNames,TypeConvertertypeConverter)throwsBeansException{
...
elseif(Map.class.isAssignableFrom(type)&&type.isInterface()){
Class<?>keyType=descriptor.getMapKeyType();
if(keyType==null||!String.class.isAssignableFrom(keyType)){
if(descriptor.isRequired()){
thrownewFatalBeanException("Keytype["+keyType+"]ofmap["+type.getName()+
"]mustbeassignableto[java.lang.String]");
}
returnnull;
}
Class<?>valueType=descriptor.getMapValueType();
if(valueType==null){
if(descriptor.isRequired()){
thrownewFatalBeanException("Novaluetypedeclaredformap["+type.getName()+"]");
}
returnnull;
}
Map<String,Object>matchingBeans=findAutowireCandidates(beanName,valueType,descriptor);
if(matchingBeans.isEmpty()){
if(descriptor.isRequired()){
raiseNoSuchBeanDefinitionException(valueType,"mapwithvaluetype"+valueType.getName(),descriptor);
}
returnnull;
}
if(autowiredBeanNames!=null){
autowiredBeanNames.addAll(matchingBeans.keySet());
}
returnmatchingBeans;
}
...
}
关键在这一句:Map
严重:CaughtexceptionwhileallowingTestExecutionListener
[org.springframework.test.context.support.DependencyInjectionTestExecutionListener@9476189]topreparetestinstance[me.arganzheng.study.spring.autowired.AutowiredTest@2d546e21]
...
Causedby:org.springframework.beans.factory.NoSuchBeanDefinitionException:Noqualifyingbeanoftype[java.lang.String]foundfordependency[mapwithvaluetypejava.lang.String]:expectedatleast1beanwhichqualifiesasautowirecandidateforthisdependency.Dependencyannotations:{@org.springframework.beans.factory.annotation.Autowired(required=true),@org.springframework.beans.factory.annotation.Qualifier(value=languageChangesMap)}
atorg.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
atorg.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843)
atorg.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
atorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
...28more
debug了一下,发现跟没有指定qualifiename是一样的执行路径。不是指定了beanname了吗?为什么还是autowiredbytype呢?仔细查看了一下才发现。DefaultListableBeanFactory的doResolveDependency方法对首先对类型做了区别:
protectedObjectdoResolveDependency(DependencyDescriptordescriptor,Class<?>type,StringbeanName,
Set<String>autowiredBeanNames,TypeConvertertypeConverter)throwsBeansException{
Objectvalue=getAutowireCandidateResolver().getSuggestedValue(descriptor);
if(value!=null){
if(valueinstanceofString){
StringstrVal=resolveEmbeddedValue((String)value);
BeanDefinitionbd=(beanName!=null&&containsBean(beanName)?getMergedBeanDefinition(beanName):null);
value=evaluateBeanDefinitionString(strVal,bd);
}
TypeConverterconverter=(typeConverter!=null?typeConverter:getTypeConverter());
return(descriptor.getField()!=null?
converter.convertIfNecessary(value,type,descriptor.getField()):
converter.convertIfNecessary(value,type,descriptor.getMethodParameter()));
}
if(type.isArray()){
Class<?>componentType=type.getComponentType();
Map<String,Object>matchingBeans=findAutowireCandidates(beanName,componentType,descriptor);
if(matchingBeans.isEmpty()){
if(descriptor.isRequired()){
raiseNoSuchBeanDefinitionException(componentType,"arrayof"+componentType.getName(),descriptor);
}
returnnull;
}
if(autowiredBeanNames!=null){
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverterconverter=(typeConverter!=null?typeConverter:getTypeConverter());
returnconverter.convertIfNecessary(matchingBeans.values(),type);
}
elseif(Collection.class.isAssignableFrom(type)&&type.isInterface()){
Class<?>elementType=descriptor.getCollectionType();
if(elementType==null){
if(descriptor.isRequired()){
thrownewFatalBeanException("Noelementtypedeclaredforcollection["+type.getName()+"]");
}
returnnull;
}
Map<String,Object>matchingBeans=findAutowireCandidates(beanName,elementType,descriptor);
if(matchingBeans.isEmpty()){
if(descriptor.isRequired()){
raiseNoSuchBeanDefinitionException(elementType,"collectionof"+elementType.getName(),descriptor);
}
returnnull;
}
if(autowiredBeanNames!=null){
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverterconverter=(typeConverter!=null?typeConverter:getTypeConverter());
returnconverter.convertIfNecessary(matchingBeans.values(),type);
}
elseif(Map.class.isAssignableFrom(type)&&type.isInterface()){
Class<?>keyType=descriptor.getMapKeyType();
if(keyType==null||!String.class.isAssignableFrom(keyType)){
if(descriptor.isRequired()){
thrownewFatalBeanException("Keytype["+keyType+"]ofmap["+type.getName()+
"]mustbeassignableto[java.lang.String]");
}
returnnull;
}
Class<?>valueType=descriptor.getMapValueType();
if(valueType==null){
if(descriptor.isRequired()){
thrownewFatalBeanException("Novaluetypedeclaredformap["+type.getName()+"]");
}
returnnull;
}
Map<String,Object>matchingBeans=findAutowireCandidates(beanName,valueType,descriptor);
if(matchingBeans.isEmpty()){
if(descriptor.isRequired()){
raiseNoSuchBeanDefinitionException(valueType,"mapwithvaluetype"+valueType.getName(),descriptor);
}
returnnull;
}
if(autowiredBeanNames!=null){
autowiredBeanNames.addAll(matchingBeans.keySet());
}
returnmatchingBeans;
}
else{
Map<String,Object>matchingBeans=findAutowireCandidates(beanName,type,descriptor);
if(matchingBeans.isEmpty()){
if(descriptor.isRequired()){
raiseNoSuchBeanDefinitionException(type,"",descriptor);
}
returnnull;
}
if(matchingBeans.size()>1){
StringprimaryBeanName=determinePrimaryCandidate(matchingBeans,descriptor);
if(primaryBeanName==null){
thrownewNoUniqueBeanDefinitionException(type,matchingBeans.keySet());
}
if(autowiredBeanNames!=null){
autowiredBeanNames.add(primaryBeanName);
}
returnmatchingBeans.get(primaryBeanName);
}
//Wehaveexactlyonematch.
Map.Entry<String,Object>entry=matchingBeans.entrySet().iterator().next();
if(autowiredBeanNames!=null){
autowiredBeanNames.add(entry.getKey());
}
returnentry.getValue();
}
}
如果是Array,Collection或者Map,则根据集合类中元素的类型来进行autowiredbytype(Map使用value的类型)。为什么这么特殊处理呢?原来,Spring是为了达到这样的目的:让你可以一次注入所有符合类型的实现,也就是说可以这样子注入:
@Autowired
privateList<Car>cars;
如果你的car有多个实现,那么都会注入进来,不会再报
org.springframework.beans.factory.NoSuchBeanDefinitionException: Nouniquebeanoftype[me.arganzheng.study.spring.autowired.Car]isdefined: expectedsinglematchingbeanbutfound2:[audi,toyota].
然而,上面的情况如果你用@Resource则不会有这个问题:
publicclassAutowiredTestextendsBaseSpringTestCase{
@Resource
@Qualifier("languageChangesMap")
privateMap<String,String>languageChangesMap;
@Test
publicvoidtestAutowired(){
assertNotNull(languageChangesMap);
System.out.println(languageChangesMap.getClass().getSimpleName());
System.out.println(languageChangesMap);
}
}
正常运行:
LinkedHashMap
{pt=pt,br=pt,jp=ja,ja=ja,ind=ind,id=ind,en-rin=en-rIn,in=en-rIn,en=en,gb=en,th=th,ar=ar,eg=ar}
当然,你如果不指定@Qualifier(“languageChangesMap”),同时fieldname不是languageChangesMap,那么还是一样报错的。
Causedby:org.springframework.beans.factory.NoSuchBeanDefinitionException:Noqualifyingbeanoftype[java.lang.String]foundfordependency[mapwithvaluetypejava.lang.String]:expectedatleast1beanwhichqualifiesasautowirecandidateforthisdependency.Dependencyannotations:{@javax.annotation.Resource(shareable=true,mappedName=,description=,name=,type=classjava.lang.Object,authenticationType=CONTAINER,lookup=)}
atorg.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
atorg.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843)
atorg.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
atorg.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:438)
atorg.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:416)
atorg.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:550)
atorg.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150)
atorg.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
atorg.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:303)
...26more
而且,@Resource也可以实现上面的List接收所有实现:
publicclassAutowiredTestextendsBaseSpringTestCase{
@Resource
@Qualifier("languageChangesMap")
privateMap<String,String>languageChangesMap;
@Resource
privateList<Car>cars;
@Test
publicvoidtestAutowired(){
assertNotNull(languageChangesMap);
System.out.println(languageChangesMap.getClass().getSimpleName());
System.out.println(languageChangesMap);
assertNotNull(cars);
System.out.println(cars.getClass().getSimpleName());
System.out.println(cars);
}
}
运行的妥妥的:
LinkedHashMap
{pt=pt,br=pt,jp=ja,ja=ja,ind=ind,id=ind,en-rin=en-rIn,in=en-rIn,en=en,gb=en,th=th,ar=ar,eg=ar}
ArrayList
[me.arganzheng.study.spring.autowired.Audi@579584da,me.arganzheng.study.spring.autowired.Toyota@19453122]
这是因为@Resource注解使用的是CommonAnnotationBeanPostProcessor处理器,跟AutowiredAnnotationBeanPostProcessor不是同一个作者[/偷笑]。这里就不分析了,感兴趣的同学可以自己看代码研究一下。
最终结论如下:
1、@Autowired和@Inject
autowiredbytype可以通过@Qualifier显式指定autowiredbyqualifiername(非集合类。注意:不是autowiredbybeanname!)
如果autowiredbytype失败(找不到或者找到多个实现),则退化为autowiredbyfieldname(非集合类)
2、@Resource
默认autowiredbyfieldname
如果autowiredbyfieldname失败,会退化为autowiredbytype
可以通过@Qualifier显式指定autowiredbyqualifiername
如果autowiredbyqualifiername失败,会退化为autowiredbyfieldname。但是这时候如果autowiredbyfieldname失败,就不会再退化为autowiredbytype了
测试工程保存在GitHub上,是标准的maven工程,感兴趣的同学可以clone到本地运行测试一下。
补充
有同事指出Spring官方文档上有这么一句话跟我的结有点冲突:
However,althoughyoucanusethisconventiontorefertospecificbeansbyname,@Autowiredisfundamentallyabouttype-driveninjectionwithoptionalsemanticqualifiers.Thismeansthatqualifiervalues,evenwiththebeannamefallback,alwayshavenarrowingsemanticswithinthesetoftypematches;theydonotsemanticallyexpressareferencetoauniquebeanid.
也就是说@Autowired即使加了@Qualifier注解,其实也是autowiredbytype。@Qualifier只是一个限定词,过滤条件而已。重新跟进了一下代码,发现确实是这样子的。Spring设计的这个@Qualifiername并不等同于beanname。他有点类似于一个tag。不过如果这个tag是唯一的化,那么其实效果上等同于beanname。实现上,Spring是先getByType,得到listcandicates,然后再根据qualifiername进行过滤。
再定义一个兰博基尼,这里使用@Qualifier指定:
packageme.arganzheng.study.spring.autowired;
importorg.springframework.beans.factory.annotation.Qualifier;
importorg.springframework.stereotype.Component;
@Component
@Qualifier("luxury")
publicclassLamborghiniimplementsCar{
}
再定义一个劳斯莱斯,这里故意用@Named指定:
packageme.arganzheng.study.spring.autowired;
importjavax.inject.Named;
importorg.springframework.stereotype.Component;
@Component
@Named("luxury")
publicclassRollsRoyceimplementsCar{
}
测试一下注入定义的豪华车:
packageme.arganzheng.study.spring.autowired;
importstaticjunit.framework.Assert.assertNotNull;
importjava.util.List;
importme.arganzheng.study.BaseSpringTestCase;
importorg.junit.Test;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Qualifier;
/**
*
*@authorzhengzhibin
*
*/
publicclassAutowiredTestextendsBaseSpringTestCase{
@Autowired
@Qualifier("luxury")
privateList<Car>luxuryCars;
@Test
publicvoidtestAutowired(){
assertNotNull(luxuryCars);
System.out.println(luxuryCars.getClass().getSimpleName());
System.out.println(luxuryCars);
}
}
运行结果如下:
ArrayList [me.arganzheng.study.spring.autowired.Lamborghini@66b875e1,me.arganzheng.study.spring.autowired.RollsRoyce@58433b76]
补充:Autowiringmodes
Spring支持四种autowire模式,当使用XML配置方式时,你可以通过autowire属性指定。
no.(Default)Noautowiring.Beanreferencesmustbedefinedviaarefelement.Changingthedefaultsettingisnotrecommendedforlargerdeployments,becausespecifyingcollaboratorsexplicitlygivesgreatercontrolandclarity.Tosomeextent,itdocumentsthestructureofasystem. byName.Autowiringbypropertyname.Springlooksforabeanwiththesamenameasthepropertythatneedstobeautowired.Forexample,ifabeandefinitionissettoautowirebyname,anditcontainsamasterproperty(thatis,ithasasetMaster(..)method),Springlooksforabeandefinitionnamedmaster,andusesittosettheproperty. byType.Allowsapropertytobeautowiredifexactlyonebeanofthepropertytypeexistsinthecontainer.Ifmorethanoneexists,afatalexceptionisthrown,whichindicatesthatyoumaynotusebyTypeautowiringforthatbean.Iftherearenomatchingbeans,nothinghappens;thepropertyisnotset. constructor.AnalogoustobyType,butappliestoconstructorarguments.Ifthereisnotexactlyonebeanoftheconstructorargumenttypeinthecontainer,afatalerrorisraised.
如果使用@Autowired、@Inject或者@Resource注解的时候,则稍微复杂一些,会有一个失败退化过程,并且引入了Qualifier。不过基本原理是一样。