精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Java Spring各種依賴注入注解的區別

開發 前端
如果使用@Autowired、@Inject或者@Resource注解的時候,則稍微復雜一些,會有一個失敗退化過程,并且引入了Qualifier。不過基本原理是一樣。

[[164298]]

Spring對于Bean的依賴注入,支持多種注解方式:

 

  1. @Resource 
  2. javax.annotation 
  3. JSR250 (Common Annotations for Java) 
  4.  
  5. @Inject 
  6. javax.inject 
  7. JSR330 (Dependency Injection for Java) 
  8.  
  9. @Autowired 
  10. org.springframework.bean.factory 
  11. Spring 

直觀上看起來,@Autowired是Spring提供的注解,其他幾個都是JDK本身內建的注解,Spring對這些注解也進行了支持。但是使用起來這三者到底有什么區別呢?筆者經過方法的測試,發現一些有意思的特性。

區別總結如下:

一、@Autowired有個required屬性,可以配置為false,這種情況下如果沒有找到對應的bean是不會拋異常的。@Inject和@Resource沒有提供對應的配置,所以必須找到否則會拋異常。

二、 @Autowired和@Inject基本是一樣的,因為兩者都是使用AutowiredAnnotationBeanPostProcessor來處理 依賴注入。但是@Resource是個例外,它使用的是CommonAnnotationBeanPostProcessor來處理依賴注入。當然,兩者 都是BeanPostProcessor。

 

  1. @Autowired@Inject 
  2. - 默認 autowired by type 
  3. - 可以 通過@Qualifier 顯式指定 autowired by qualifier name。 
  4. - 如果 autowired by type 失?。ㄕ也坏交蛘哒业蕉鄠€實現),則退化為autowired by field name 
  5.  
  6. @Resource 
  7. - 默認 autowired by field name 
  8. - 如果 autowired by field name失敗,會退化為 autowired by type 
  9. - 可以 通過@Qualifier 顯式指定 autowired by qualifier name 
  10. - 如果 autowired by qualifier name失敗,會退化為 autowired by field name。但是這時候如果 autowired by field name失敗,就不會再退化為autowired by type了。 

TIPS Qualified name VS Bean name

在Spring設計中,Qualified name并不等同于Bean name,后者必須是***的,但是前者類似于tag或者group的作用,對特定的bean進行分類??梢赃_到getByTag(group)的效果。對 于XML配置的bean,可以通過id屬性指定bean name(如果沒有指定,默認使用類名首字母小寫),通過標簽指定qualifier name:

  1. <bean id="lamborghini" class="me.arganzheng.study.spring.autowired.Lamborghini"
  2.     <qualifier value="luxury"/> 
  3.     <!-- inject any dependencies required by this bean --> 
  4. </bean> 

如果是通過注解方式,那么可以通過@Qualifier注解指定qualifier name,通過@Named或者@Component(@Service,@Repository等)的value值指定bean name:

 

  1. @Component("lamborghini"
  2. @Qualifier("luxury"
  3. public class Lamborghini implements Car { 

或者

 

  1. @Component 
  2. @Named("lamborghini"
  3. @Qualifier("luxury"
  4. public class Lamborghini implements Car { 

同樣,如果沒有指定bean name,那么Spring會默認是用類名首字母小寫(Lamborghini=>lamborghini)。

三、 通過Anotation注入依賴的方式在XML注入方式之前進行。如果對同一個bean的依賴同時使用了兩種注入方式,那么XML的優先。但是不同擔心通過Anotation注入的依賴沒法注入XML中配置的bean,依賴注入是在bean的注冊之后進行的。

四、目前的autowired by type方式(筆者用的是3.2.3.RELEASE版本),Spring的AutowiredAnnotationBeanPostProcessor 實現都是有”bug”的,也就是說@Autowired和@Inject都是有坑的(稱之為坑,不稱之為bug是因為貌似是故意的。。)。這是來源于線上 的一個bug,也是這邊文章的寫作原因。現場如下:

application-context.xml中有如下定義:

 

  1. <xml version="1.0" encoding="UTF-8"?> 
  2. <beans xmlns="http://www.springframework.org/schema/beans" 
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 
  4.     xmlns:context="http://www.springframework.org/schema/context" 
  5.     xmlns:util="http://www.springframework.org/schema/util" 
  6.     xsi:schemaLocation=" 
  7.         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
  8.         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
  9.         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd 
  10.         http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"> 
  11.  
  12.     <context:annotation-config /> 
  13.  
  14.     <context:component-scan base-package="me.arganzheng.study" /> 
  15.  
  16.     <util:constant id="en" 
  17.         static-field="me.arganzheng.study.spring.autowired.Constants.Language.EN" /> 
  18.     <util:constant id="ja" 
  19.         static-field="me.arganzheng.study.spring.autowired.Constants.Language.JP" /> 
  20.     <util:constant id="ind" 
  21.         static-field="me.arganzheng.study.spring.autowired.Constants.Language.IND" /> 
  22.     <util:constant id="pt" 
  23.         static-field="me.arganzheng.study.spring.autowired.Constants.Language.PT" /> 
  24.     <util:constant id="th" 
  25.         static-field="me.arganzheng.study.spring.autowired.Constants.Language.TH" /> 
  26.     <util:constant id="ar" 
  27.         static-field="me.arganzheng.study.spring.autowired.Constants.Language.AR" /> 
  28.     <util:constant id="en-rIn" 
  29.         static-field="me.arganzheng.study.spring.autowired.Constants.Language.EN_RIN" /> 
  30.  
  31.     <util:map id="languageChangesMap" key-type="java.lang.String" 
  32.         value-type="java.lang.String"
  33.         <entry key="pt" value="pt" /> 
  34.         <entry key="br" value="pt" /> 
  35.         <entry key="jp" value="ja" /> 
  36.         <entry key="ja" value="ja" /> 
  37.         <entry key="ind" value="ind" /> 
  38.         <entry key="id" value="ind" /> 
  39.         <entry key="en-rin" value="en-rIn" /> 
  40.         <entry key="in" value="en-rIn" /> 
  41.         <entry key="en" value="en" /> 
  42.         <entry key="gb" value="en" /> 
  43.         <entry key="th" value="th" /> 
  44.         <entry key="ar" value="ar" /> 
  45.         <entry key="eg" value="ar" /> 
  46.     </util:map> 
  47.  
  48. </beans> 

其中static-field應用的常量定義在如下類中:

 

  1. package me.arganzheng.study.spring.autowired; 
  2.  
  3. public interface Constants { 
  4.  
  5.     public interface Language { 
  6.         public static final String EN = "CommonConstants.LANG_ENGLISH"
  7.         public static final String JP = "CommonConstants.LANG_JAPANESE"
  8.         public static final String IND = "CommonConstants.LANG_INDONESIAN"
  9.         public static final String PT = "CommonConstants.LANG_PORTUGUESE"
  10.         public static final String TH = "CommonConstants.LANG_THAI"
  11.         public static final String EN_RIN = "CommonConstants.LANG_ENGLISH_INDIA"
  12.         public static final String AR = "CommonConstants.LANG_Arabic"
  13.     } 

然后如果我們在代碼中如下聲明依賴:

 

  1. public class AutowiredTest extends BaseSpringTestCase { 
  2.  
  3.     @Autowired 
  4.     private Map<String, String> languageChangesMap; 
  5.  
  6.     @Test 
  7.     public void testAutowired() { 
  8.         notNull(languageChangesMap); 
  9.         System.out.println(languageChangesMap.getClass().getSimpleName()); 
  10.         System.out.println(languageChangesMap); 
  11.     } 

Guess what,詭異的事情發生了!

運行結果如下:

  1. LinkedHashMap 
  2. {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

  1. 嚴重: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@5c51ee0a] to prepare test instance [me.arganzheng.study.spring.autowired.AutowiredTest@6e301e0
  2. org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'me.arganzheng.study.spring.autowired.AutowiredTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.util.Map me.arganzheng.study.spring.autowired.AutowiredTest.languageChangesMap; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} 
  1. ... 
  2. ed by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} 
  3. at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986
  4. at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843
  5. at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768
  6. at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486
  7. ... 28 more 

debug了一下,發現確實是Spring的一個bug。在DefaultListableBeanFactory的這個方法出問題了:

 

  1. protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName, 
  2.             Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException { 
  3.         ...     
  4.  
  5.         else if (Map.class.isAssignableFrom(type) && type.isInterface()) { 
  6.             Class<?> keyType = descriptor.getMapKeyType(); 
  7.             if (keyType == null || !String.class.isAssignableFrom(keyType)) { 
  8.                 if (descriptor.isRequired()) { 
  9.                     throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() + 
  10.                             "] must be assignable to [java.lang.String]"); 
  11.                 } 
  12.                 return null
  13.             } 
  14.             Class<?> valueType = descriptor.getMapValueType(); 
  15.             if (valueType == null) { 
  16.                 if (descriptor.isRequired()) { 
  17.                     throw new FatalBeanException("No value type declared for map [" + type.getName() + "]"); 
  18.                 } 
  19.                 return null
  20.             } 
  21.             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor); 
  22.             if (matchingBeans.isEmpty()) { 
  23.                 if (descriptor.isRequired()) { 
  24.                     raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor); 
  25.                 } 
  26.                 return null
  27.             } 
  28.             if (autowiredBeanNames != null) { 
  29.                 autowiredBeanNames.addAll(matchingBeans.keySet()); 
  30.             } 
  31.             return matchingBeans; 
  32.         } 
  33.         ... 
  34.     } 

關鍵在這一句:Map

  1. 嚴重: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@9476189] to prepare test instance [me.arganzheng.study.spring.autowired.AutowiredTest@2d546e21
  2. ... 
  3. Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=languageChangesMap)} 
  4.     at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986
  5.     at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843
  6.     at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768
  7.     at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486
  8.     ... 28 more 

debug了一下,發現跟沒有指定qualifie name是一樣的執行路徑。不是指定了bean name了嗎?為什么還是autowired by type呢?仔細查看了一下才發現。DefaultListableBeanFactory的doResolveDependency方法對首先對類型做 了區別:

 

  1. protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName, 
  2.             Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException { 
  3.  
  4.         Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); 
  5.         if (value != null) { 
  6.             if (value instanceof String) { 
  7.                 String strVal = resolveEmbeddedValue((String) value); 
  8.                 BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null); 
  9.                 value = evaluateBeanDefinitionString(strVal, bd); 
  10.             } 
  11.             TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); 
  12.             return (descriptor.getField() != null ? 
  13.                     converter.convertIfNecessary(value, type, descriptor.getField()) : 
  14.                     converter.convertIfNecessary(value, type, descriptor.getMethodParameter())); 
  15.         } 
  16.  
  17.         if (type.isArray()) { 
  18.             Class<?> componentType = type.getComponentType(); 
  19.             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, descriptor); 
  20.             if (matchingBeans.isEmpty()) { 
  21.                 if (descriptor.isRequired()) { 
  22.                     raiseNoSuchBeanDefinitionException(componentType, "array of " + componentType.getName(), descriptor); 
  23.                 } 
  24.                 return null
  25.             } 
  26.             if (autowiredBeanNames != null) { 
  27.                 autowiredBeanNames.addAll(matchingBeans.keySet()); 
  28.             } 
  29.             TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); 
  30.             return converter.convertIfNecessary(matchingBeans.values(), type); 
  31.         } 
  32.         else if (Collection.class.isAssignableFrom(type) && type.isInterface()) { 
  33.             Class<?> elementType = descriptor.getCollectionType(); 
  34.             if (elementType == null) { 
  35.                 if (descriptor.isRequired()) { 
  36.                     throw new FatalBeanException("No element type declared for collection [" + type.getName() + "]"); 
  37.                 } 
  38.                 return null
  39.             } 
  40.             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, descriptor); 
  41.             if (matchingBeans.isEmpty()) { 
  42.                 if (descriptor.isRequired()) { 
  43.                     raiseNoSuchBeanDefinitionException(elementType, "collection of " + elementType.getName(), descriptor); 
  44.                 } 
  45.                 return null
  46.             } 
  47.             if (autowiredBeanNames != null) { 
  48.                 autowiredBeanNames.addAll(matchingBeans.keySet()); 
  49.             } 
  50.             TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); 
  51.             return converter.convertIfNecessary(matchingBeans.values(), type); 
  52.         } 
  53.         else if (Map.class.isAssignableFrom(type) && type.isInterface()) { 
  54.             Class<?> keyType = descriptor.getMapKeyType(); 
  55.             if (keyType == null || !String.class.isAssignableFrom(keyType)) { 
  56.                 if (descriptor.isRequired()) { 
  57.                     throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() + 
  58.                             "] must be assignable to [java.lang.String]"); 
  59.                 } 
  60.                 return null
  61.             } 
  62.             Class<?> valueType = descriptor.getMapValueType(); 
  63.             if (valueType == null) { 
  64.                 if (descriptor.isRequired()) { 
  65.                     throw new FatalBeanException("No value type declared for map [" + type.getName() + "]"); 
  66.                 } 
  67.                 return null
  68.             } 
  69.             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor); 
  70.             if (matchingBeans.isEmpty()) { 
  71.                 if (descriptor.isRequired()) { 
  72.                     raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor); 
  73.                 } 
  74.                 return null
  75.             } 
  76.             if (autowiredBeanNames != null) { 
  77.                 autowiredBeanNames.addAll(matchingBeans.keySet()); 
  78.             } 
  79.             return matchingBeans; 
  80.         } 
  81.         else { 
  82.             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); 
  83.             if (matchingBeans.isEmpty()) { 
  84.                 if (descriptor.isRequired()) { 
  85.                     raiseNoSuchBeanDefinitionException(type, "", descriptor); 
  86.                 } 
  87.                 return null
  88.             } 
  89.             if (matchingBeans.size() > 1) { 
  90.                 String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor); 
  91.                 if (primaryBeanName == null) { 
  92.                     throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet()); 
  93.                 } 
  94.                 if (autowiredBeanNames != null) { 
  95.                     autowiredBeanNames.add(primaryBeanName); 
  96.                 } 
  97.                 return matchingBeans.get(primaryBeanName); 
  98.             } 
  99.             // We have exactly one match. 
  100.             Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next(); 
  101.             if (autowiredBeanNames != null) { 
  102.                 autowiredBeanNames.add(entry.getKey()); 
  103.             } 
  104.             return entry.getValue(); 
  105.         } 
  106.     } 

如果是Array,Collection或者Map,則根據集合類中元素的類型來進行autowired by type(Map使用value的類型)。為什么這么特殊處理呢?原來,Spring是為了達到這樣的目的:讓你可以一次注入所有符合類型的實現,也就是 說可以這樣子注入:

  1. @Autowired 
  2. private List<Car> cars; 

如果你的car有多個實現,那么都會注入進來,不會再報

 

  1. org.springframework.beans.factory.NoSuchBeanDefinitionException: 
  2. No unique bean of type [me.arganzheng.study.spring.autowired.Car] is defined: 
  3. expected single matching bean but found 2: [audi, toyota]. 
  4.  
  5. 然而,上面的情況如果你用@Resource則不會有這個問題: 
  6.  
  7. public class AutowiredTest extends BaseSpringTestCase { 
  8.  
  9.     @Resource 
  10.     @Qualifier("languageChangesMap"
  11.     private Map<String, String> languageChangesMap; 
  12.  
  13.     @Test 
  14.     public void testAutowired() { 
  15.         assertNotNull(languageChangesMap); 
  16.         System.out.println(languageChangesMap.getClass().getSimpleName()); 
  17.         System.out.println(languageChangesMap); 
  18.     } 

正常運行:

  1. LinkedHashMap 
  2. {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”),同時field name不是languageChangesMap,那么還是一樣報錯的。

 

  1. Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.annotation.Resource(shareable=true, mappedName=, description=, name=, type=class java.lang.Object, authenticationType=CONTAINER, lookup=)} 
  2. at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986
  3. at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843
  4. at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768
  5. at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:438
  6. at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:416
  7. at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:550
  8. at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150
  9. at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87
  10. at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:303
  11. ... 26 more 

而且,@Resource也可以實現上面的List接收所有實現:

 

  1. public class AutowiredTest extends BaseSpringTestCase { 
  2.  
  3.     @Resource 
  4.     @Qualifier("languageChangesMap"
  5.     private Map<String, String> languageChangesMap; 
  6.  
  7.     @Resource 
  8.     private List<Car> cars; 
  9.  
  10.     @Test 
  11.     public void testAutowired() { 
  12.         assertNotNull(languageChangesMap); 
  13.         System.out.println(languageChangesMap.getClass().getSimpleName()); 
  14.         System.out.println(languageChangesMap); 
  15.  
  16.         assertNotNull(cars); 
  17.         System.out.println(cars.getClass().getSimpleName()); 
  18.         System.out.println(cars); 
  19.     } 

運行的妥妥的:

  1. LinkedHashMap 
  2. {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} 
  3. ArrayList 
  4. [me.arganzheng.study.spring.autowired.Audi@579584da, me.arganzheng.study.spring.autowired.Toyota@19453122

這是因為@Resource注解使用的是CommonAnnotationBeanPostProcessor處理器,跟 AutowiredAnnotationBeanPostProcessor不是同一個作者[/偷笑]。這里就不分析了,感興趣的同學可以自己看代碼研究 一下。

最終結論如下:

1、@Autowired和@Inject

autowired by type 可以 通過@Qualifier 顯式指定 autowired by qualifier name(非集合類。注意:不是autowired by bean name?。?br /> 如果 autowired by type 失?。ㄕ也坏交蛘哒业蕉鄠€實現),則退化為autowired by field name(非集合類)

2、@Resource

默認 autowired by field name
如果 autowired by field name失敗,會退化為 autowired by type
可以 通過@Qualifier 顯式指定 autowired by qualifier name
如果 autowired by qualifier name失敗,會退化為 autowired by field name。但是這時候如果 autowired by field name失敗,就不會再退化為autowired by type了

測試工程保存在GitHub上,是標準的maven工程,感興趣的同學可以clone到本地運行測試一下。

補充

有同事指出Spring官方文檔上有這么一句話跟我的結有點沖突:

However, although you can use this convention to refer to specific beans by name, @Autowired is fundamentally about type-driven injection with optional semantic qualifiers. This means that qualifier values, even with the bean name fallback, always have narrowing semantics within the set of type matches; they do not semantically express a reference to a unique bean id.

也就是說@Autowired即使加了@Qualifier注解,其實也是autowired by type。@Qualifier只是一個限定詞,過濾條件而已。重新跟進了一下代碼,發現確實是這樣子的。Spring設計的這個 @Qualifier name 并不等同于 bean name。他有點類似于一個tag。不過如果這個tag是***的化,那么其實效果上等同于bean name。實現上,Spring是先getByType,得到list candicates,然后再根據qualifier name進行過濾。

再定義一個蘭博基尼,這里使用@Qualifier指定:

 

  1. package me.arganzheng.study.spring.autowired; 
  2.  
  3. import org.springframework.beans.factory.annotation.Qualifier; 
  4. import org.springframework.stereotype.Component; 
  5.  
  6. @Component 
  7. @Qualifier("luxury"
  8. public class Lamborghini implements Car { 
  9.  

再定義一個勞斯萊斯,這里故意用@Named指定:

 

  1. package me.arganzheng.study.spring.autowired; 
  2.  
  3. import javax.inject.Named; 
  4.  
  5. import org.springframework.stereotype.Component; 
  6.  
  7. @Component 
  8. @Named("luxury"
  9. public class RollsRoyce implements Car { 
  10.  

測試一下注入定義的豪華車:

 

  1. package me.arganzheng.study.spring.autowired; 
  2.  
  3. import static junit.framework.Assert.assertNotNull; 
  4.  
  5. import java.util.List; 
  6.  
  7. import me.arganzheng.study.BaseSpringTestCase; 
  8.  
  9. import org.junit.Test; 
  10. import org.springframework.beans.factory.annotation.Autowired; 
  11. import org.springframework.beans.factory.annotation.Qualifier; 
  12.  
  13. /** 
  14. * 
  15. * @author zhengzhibin 
  16. * 
  17. */ 
  18. public class AutowiredTest extends BaseSpringTestCase { 
  19.  
  20.     @Autowired 
  21.     @Qualifier("luxury"
  22.     private List<Car> luxuryCars; 
  23.  
  24.     @Test 
  25.     public void testAutowired() { 
  26.  
  27.         assertNotNull(luxuryCars); 
  28.         System.out.println(luxuryCars.getClass().getSimpleName()); 
  29.         System.out.println(luxuryCars); 
  30.     } 
  31.  

運行結果如下:

  1. ArrayList 
  2. [me.arganzheng.study.spring.autowired.Lamborghini@66b875e1, me.arganzheng.study.spring.autowired.RollsRoyce@58433b76

補充:Autowiring modes

Spring支持四種autowire模式,當使用XML配置方式時,你可以通過autowire屬性指定。

  1. no. (Default) No autowiring. Bean references must be defined via a ref element. Changing the default setting is not recommended for larger deployments, because specifying collaborators explicitly gives greater control and clarity. To some extent, it documents the structure of a system. 
  2. byName. Autowiring by property name. Spring looks for a bean with the same name as the property that needs to be autowired. For example, if a bean definition is set to autowire by name, and it contains a master property (that is, it has a setMaster(..) method), Spring looks for a bean definition named master, and uses it to set the property. 
  3. byType. Allows a property to be autowired if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown, which indicates that you may not use byType autowiring for that bean. If there are no matching beans, nothing happens; the property is not set. 
  4. constructor. Analogous to byType, but applies to constructor arguments. If there is not exactly one bean of the constructor argument type in the container, a fatal error is raised. 

如果使用@Autowired、@Inject或者@Resource注解的時候,則稍微復雜一些,會有一個失敗退化過程,并且引入了Qualifier。不過基本原理是一樣。

責任編輯:王雪燕 來源: 徐劉根
相關推薦

2011-05-31 10:00:21

Android Spring 依賴注入

2023-07-11 09:14:12

Beanquarkus

2009-06-15 17:48:32

Spring注解注入屬性

2011-04-15 09:44:45

Spring

2022-04-30 08:50:11

控制反轉Spring依賴注入

2020-08-06 00:14:16

Spring IoC依賴注入開發

2009-09-08 15:22:20

Spring依賴注入

2011-03-01 13:45:41

Spring3Annotation

2022-12-29 08:54:53

依賴注入JavaScript

2023-10-07 08:35:07

依賴注入Spring

2025-06-12 05:00:00

@Autowired自動裝配實現機制

2015-09-02 11:22:36

JavaScript實現思路

2021-07-29 06:55:03

Spring@AutowriedbyType注入

2023-09-14 08:16:50

Lazy注解null

2024-08-26 08:52:41

2012-12-25 10:53:09

2021-12-15 09:17:12

Spring依賴注入面試題

2022-08-24 07:06:36

SpringSetter項目

2022-04-11 09:02:18

Swift依賴注

2014-07-08 14:05:48

DaggerAndroid依賴
點贊
收藏

51CTO技術棧公眾號

欧美孕妇与黑人孕交| 亚洲国产成人精品久久| 亚洲欧洲一区二区在线观看| 国产又粗又大又爽视频| 精品9999| 色阁综合伊人av| 伊人久久一区二区三区| 日本精品在线中文字幕| 亚洲精品日产精品乱码不卡| 精品国产二区在线| 在线观看国产小视频| 在线观看的日韩av| 色黄久久久久久| av无码一区二区三区| xxxxx.日韩| 五月综合激情日本mⅴ| 亚洲欧美影院| 牛牛热在线视频| 国产成人精品免费| 国产精品色视频| 国产成人精品片| 亚洲男女av一区二区| 日韩国产欧美区| 原创真实夫妻啪啪av| 综合在线影院| 午夜精品久久久久久久蜜桃app| 亚洲一区三区视频在线观看| 青青草娱乐在线| 国产aⅴ精品一区二区三区色成熟| 国产精品第8页| 欧美精品亚洲精品日韩精品| 亚洲老妇激情| 最近2019中文字幕mv免费看| 中文字幕一区二区三区人妻不卡| 欧美日韩午夜电影网| 欧美日韩国产不卡| 色婷婷综合久久久久中文字幕| av中文字幕在线看| 亚洲激情五月婷婷| 在线看视频不卡| 成年人免费在线视频| 91丨九色丨尤物| 韩国成人动漫在线观看| 亚洲精品第五页| 国产福利不卡视频| 91中文精品字幕在线视频| 最近中文字幕免费观看| 视频在线观看一区| 日韩av免费在线播放| 天天综合网久久综合网| 亚洲一区日韩| 18一19gay欧美视频网站| 国产在线观看99| 国内精品久久久久久久影视麻豆| 久久伊人精品视频| 日韩成人短视频| 91精品推荐| 久久国产精品99国产精| 午夜爽爽爽男女免费观看| 99热在线成人| 久久国产精品久久久久久久久久| 精品在线观看一区| 99精品综合| 成人97在线观看视频| √天堂中文官网8在线| 羞羞色午夜精品一区二区三区| 深夜成人在线观看| 女同久久另类69精品国产| 99久久久久久中文字幕一区| 久久精品视频亚洲| 久草国产在线视频| 国产欧美不卡| 国产精品观看在线亚洲人成网| 中文字幕一区二区久久人妻| 精品一区二区三区在线播放视频 | 天堂资源在线亚洲视频| 福利视频在线导航| 中文字幕亚洲成人| 在线观看18视频网站| 精品精品导航| 日韩欧美一区二区在线| 欧美三级理论片| 日韩成人在线观看视频| 亚洲国产天堂网精品网站| 欧美 变态 另类 人妖| 欧美伦理影院| 色综合久久悠悠| 久久免费激情视频| 久久99精品国产麻豆不卡| 成人羞羞视频免费| 极品白浆推特女神在线观看 | 国产欧美自拍| 日韩视频一区二区三区| 中文字幕在线播放视频| 色88久久久久高潮综合影院| 色综合久久久久久中文网| 久久国产视频一区| 国产制服丝袜一区| 久久久综合亚洲91久久98| 欧美日韩视频在线播放| 午夜久久久影院| 另类小说第一页| 中文字幕一区二区三区日韩精品| 日韩成人av一区| 我要看黄色一级片| 久久久久久久欧美精品| 91情侣在线视频| 久草在现在线| 亚洲观看高清完整版在线观看| 国产成人无码一二三区视频| 久久视频免费| 国产一区二区三区18| 久久久久久蜜桃| 麻豆精品在线播放| 久久精品日产第一区二区三区精品版 | 国产三级精品三级在线| 欧美挤奶吃奶水xxxxx| 久久亚洲精品毛片| 亚洲大尺度在线观看| 成人网在线播放| 伊人久久婷婷色综合98网| 国产美女高潮在线观看| 91精品国产色综合久久ai换脸| 中文字幕国产综合| 在线观看视频免费一区二区三区| 成人在线激情视频| 可以在线观看的av| 午夜伊人狠狠久久| 熟妇女人妻丰满少妇中文字幕| 国产在线日韩精品| 38少妇精品导航| 丰满少妇一级片| 亚洲日本在线观看| 一女二男3p波多野结衣| 久久不见久久见中文字幕免费| 久久久久九九九九| 精品人妻少妇AV无码专区 | 久久久全国免费视频| 激情文学综合插| 亚洲欧美日韩国产成人综合一二三区 | xf在线a精品一区二区视频网站| 免费国产成人看片在线| 国产一区二区色噜噜| 亚洲香蕉伊综合在人在线视看| 在线观看免费国产视频| 99视频精品在线| 精品欧美一区免费观看α√| 美国十次av导航亚洲入口| 久久久久久久97| 亚洲AV无码一区二区三区少妇| 亚洲欧美一区二区久久| 不用播放器的免费av| 色喇叭免费久久综合| 国产专区精品视频| av软件在线观看| 日韩三级免费观看| 国产亚洲欧美精品久久久久久| 国产一区二区按摩在线观看| 成人在线免费观看网址| 日韩成人精品| 韩国日本不卡在线| 天堂av在线7| 色猫猫国产区一区二在线视频| 国产人妻大战黑人20p| 久久先锋资源| 夜夜春亚洲嫩草影视日日摸夜夜添夜| 久久人体av| 久久精品一偷一偷国产| av资源免费看| 亚洲国产精品精华液网站| 国产精品成人无码专区| 一区二区日韩免费看| 欧美精品一区二区三区在线看午夜 | www日本在线| 亚洲成人免费av| 亚欧洲乱码视频| 久久99最新地址| www.夜夜爱| 任你躁在线精品免费| 国产精品成人一区二区三区吃奶 | 中文字幕一区三区| 日本高清免费观看| 亚洲精品乱码| 日韩三级电影免费观看| 日韩在线成人| 欧美一级视频一区二区| seseavlu视频在线| 日韩一区二区三区四区| xxxx.国产| 中文字幕一区二| 一区二区三区少妇| 卡一卡二国产精品| 欧美精品在欧美一区二区| 天天久久夜夜| 成人女保姆的销魂服务| 国产精品yjizz视频网| 国产一区二区精品丝袜| 亚洲av少妇一区二区在线观看 | 日韩大尺度在线观看| 国产精品日韩欧美综合| 黑人玩欧美人三根一起进| 亚洲一区二区福利| xxxwww在线观看| 欧美视频自拍偷拍| 日韩欧美不卡视频| 中文字幕一区av| 日本免费福利视频| 韩国毛片一区二区三区| 男人揉女人奶房视频60分| 图片小说视频色综合| 麻豆传媒一区| 色播一区二区| 国产啪精品视频网站| sm捆绑调教国产免费网站在线观看| 最近2019免费中文字幕视频三| 天天射天天操天天干| 日韩一二在线观看| 久久久久久无码精品大片| 夜夜揉揉日日人人青青一国产精品| 美女爆乳18禁www久久久久久| 国产成人aaa| 欧美丝袜在线观看| 青娱乐精品在线视频| 免费无码不卡视频在线观看| 午夜精品av| 免费看av软件| 成人一级毛片| 欧美福利精品| 国产成人高清精品免费5388| 成人中文字幕在线观看| 99re久久| 日韩av片永久免费网站| zzzwww在线看片免费| 欧美日韩国产va另类| 成人av黄色| 久久伊人免费视频| 日本最新在线视频| 在线播放日韩专区| 欧洲综合视频| 亚洲精品久久视频| 欧美自拍第一页| 精品盗摄一区二区三区| 亚洲国产视频一区二区三区| 欧美一区二区三区在线电影| 亚洲天堂中文网| 欧美日韩中文字幕一区| 亚洲 国产 日韩 欧美| 日本韩国欧美一区| 欧美brazzers| 欧美日韩一区久久| 日本欧美www| 欧美视频在线不卡| 在线观看国产黄| 911精品国产一区二区在线| 一级片免费观看视频| 欧美日本视频在线| 91麻豆成人精品国产| 制服丝袜亚洲播放| 精品久久久久中文慕人妻| 精品国产乱码久久久久久影片| 亚洲经典一区二区三区| 精品久久久久av影院| 五月婷婷开心中文字幕| 亚洲男人天堂2024| av网站大全在线观看| 日韩视频永久免费观看| 日本中文字幕中出在线| 欧美—级a级欧美特级ar全黄| 18video性欧美19sex高清| 2019精品视频| 精品欧美一区二区三区在线观看| 国产成人a亚洲精品| 国产福利91精品一区二区| 91免费高清视频| 国产成人aa在线观看网站站| 欧美高清性xxxxhdvideosex| 欧美一级精品| 肉大捧一出免费观看网站在线播放| 在线免费高清一区二区三区| 免费在线观看毛片网站| 久久99久久久久| 蜜臀av粉嫩av懂色av| 国产婷婷一区二区| 黄视频网站免费看| 亚洲大片精品永久免费| 欧美国产一级片| 日韩亚洲欧美中文三级| 青青草娱乐在线| 久久福利网址导航| 欧美裸体视频| 成人美女av在线直播| 国产一级成人av| 一本一生久久a久久精品综合蜜 | 一区二区三区在线观看欧美| 国产黄色片视频| 欧美视频一区二区| 亚洲高清视频在线播放| 亚洲人精品午夜在线观看| 午夜在线激情影院| 日韩av手机在线看| 日韩中文字幕在线一区 | 中文在线日韩| 激情视频综合网| 国产成+人+日韩+欧美+亚洲| 国产黄片一区二区三区| 亚洲精品水蜜桃| 亚洲在线视频播放| 国产视频精品在线| bt在线麻豆视频| 国产精品久久久久久亚洲影视 | 日产电影一区二区三区| 欧美丝袜丝交足nylons图片| 婷婷av一区二区三区| 精品国产一区二区在线| 狠狠操一区二区三区| 成人黄在线观看| 欧美精品momsxxx| 真人抽搐一进一出视频| 精品影院一区二区久久久| 少妇按摩一区二区三区| 一区二区三区高清在线| 一区二区美女视频| 亚洲色图偷窥自拍| 亚洲电影观看| 波多野结衣精品久久| 天天超碰亚洲| gogogo高清免费观看在线视频| 久久网站热最新地址| 国产精品99精品| 日韩欧美综合一区| 成人在线直播| 成人黄色免费片| 久久在线电影| 成人亚洲精品777777大片| 久久久久久久网| 成人精品免费在线观看| 精品第一国产综合精品aⅴ| 污视频免费在线观看| 亚洲一区久久久| 国产精品久久久久久| 五月天激情视频在线观看| 久久久久亚洲综合| 无码人妻丰满熟妇精品区| 日韩精品极品在线观看| av资源在线看片| 国产一区二区精品在线| 亚洲美女一区| 国产精品久久久久久久无码| 亚洲高清不卡在线观看| 日韩在线观看视频网站| 欧美激情欧美激情在线五月| 亚洲天堂中文字幕在线观看| 老司机激情视频| 成人天堂资源www在线| 国产在线综合网| 亚洲国产精久久久久久| 波多野结衣视频一区二区| 久久99精品久久久久子伦 | 亚洲成av人在线观看| 人妻偷人精品一区二区三区| 91精品国产91久久久久久吃药| 全球av集中精品导航福利| 日本精品www| 国产精品你懂的在线欣赏| 亚洲一线在线观看| 欧美xxxx综合视频| 豆花视频一区二区| 1024av视频| 国产亚洲成aⅴ人片在线观看| 波多野结衣激情视频| 日韩中文字幕网站| 97久久超碰| 黄色高清无遮挡| 亚洲你懂的在线视频| 高h震动喷水双性1v1| 欧美一区二三区| 日韩美女一区二区三区在线观看| 51自拍视频在线观看| 亚洲国产欧美在线| 牛牛澡牛牛爽一区二区| 91免费电影网站| 国产精品久久久久久模特 | 国产日韩精品综合网站| 欧美激情无毛| 国产精品成人一区二区三区电影毛片 | 国产精品一区二区在线观看网站| 久久久久噜噜噜亚洲熟女综合| 亚洲毛片在线免费观看| 亚洲国产天堂| 日韩在线一级片| 国产精品福利一区| 无码精品黑人一区二区三区| 91精品国产自产在线| 99精品国产99久久久久久福利| www.日本高清视频| 亚洲精品v欧美精品v日韩精品| 福利一区二区免费视频| 青青在线免费观看| 国产精品乱子久久久久| 午夜福利视频一区二区|