Java Spring各種依賴注入注解的區(qū)別
Spring對于Bean的依賴注入,支持多種注解方式:
- @Resource
- javax.annotation
- JSR250 (Common Annotations for Java)
- @Inject
- javax.inject
- JSR330 (Dependency Injection for Java)
- @Autowired
- org.springframework.bean.factory
- Spring
直觀上看起來,@Autowired是Spring提供的注解,其他幾個(gè)都是JDK本身內(nèi)建的注解,Spring對這些注解也進(jìn)行了支持。但是使用起來這三者到底有什么區(qū)別呢?筆者經(jīng)過方法的測試,發(fā)現(xiàn)一些有意思的特性。
區(qū)別總結(jié)如下:
一、@Autowired有個(gè)required屬性,可以配置為false,這種情況下如果沒有找到對應(yīng)的bean是不會拋異常的。@Inject和@Resource沒有提供對應(yīng)的配置,所以必須找到否則會拋異常。
二、 @Autowired和@Inject基本是一樣的,因?yàn)閮烧叨际鞘褂肁utowiredAnnotationBeanPostProcessor來處理 依賴注入。但是@Resource是個(gè)例外,它使用的是CommonAnnotationBeanPostProcessor來處理依賴注入。當(dāng)然,兩者 都是BeanPostProcessor。
- @Autowired和@Inject
- - 默認(rèn) autowired by type
- - 可以 通過@Qualifier 顯式指定 autowired by qualifier name。
- - 如果 autowired by type 失?。ㄕ也坏交蛘哒业蕉鄠€(gè)實(shí)現(xiàn)),則退化為autowired by field name
- @Resource
- - 默認(rèn) autowired by field name
- - 如果 autowired by field name失敗,會退化為 autowired by type
- - 可以 通過@Qualifier 顯式指定 autowired by qualifier name
- - 如果 autowired by qualifier name失敗,會退化為 autowired by field name。但是這時(shí)候如果 autowired by field name失敗,就不會再退化為autowired by type了。
TIPS Qualified name VS Bean name
在Spring設(shè)計(jì)中,Qualified name并不等同于Bean name,后者必須是***的,但是前者類似于tag或者group的作用,對特定的bean進(jìn)行分類??梢赃_(dá)到getByTag(group)的效果。對 于XML配置的bean,可以通過id屬性指定bean name(如果沒有指定,默認(rèn)使用類名首字母小寫),通過標(biāo)簽指定qualifier name:
- <bean id="lamborghini" class="me.arganzheng.study.spring.autowired.Lamborghini">
- <qualifier value="luxury"/>
- <!-- inject any dependencies required by this bean -->
- </bean>
如果是通過注解方式,那么可以通過@Qualifier注解指定qualifier name,通過@Named或者@Component(@Service,@Repository等)的value值指定bean name:
- @Component("lamborghini")
- @Qualifier("luxury")
- public class Lamborghini implements Car {
- }
或者
- @Component
- @Named("lamborghini")
- @Qualifier("luxury")
- public class Lamborghini implements Car {
- }
同樣,如果沒有指定bean name,那么Spring會默認(rèn)是用類名首字母小寫(Lamborghini=>lamborghini)。
三、 通過Anotation注入依賴的方式在XML注入方式之前進(jìn)行。如果對同一個(gè)bean的依賴同時(shí)使用了兩種注入方式,那么XML的優(yōu)先。但是不同擔(dān)心通過Anotation注入的依賴沒法注入XML中配置的bean,依賴注入是在bean的注冊之后進(jìn)行的。
四、目前的autowired by type方式(筆者用的是3.2.3.RELEASE版本),Spring的AutowiredAnnotationBeanPostProcessor 實(shí)現(xiàn)都是有”bug”的,也就是說@Autowired和@Inject都是有坑的(稱之為坑,不稱之為bug是因?yàn)槊菜剖枪室獾摹?。)。這是來源于線上 的一個(gè)bug,也是這邊文章的寫作原因?,F(xiàn)場如下:
application-context.xml中有如下定義:
- <xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="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/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
- http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">
- <context:annotation-config />
- <context:component-scan base-package="me.arganzheng.study" />
- <util:constant id="en"
- static-field="me.arganzheng.study.spring.autowired.Constants.Language.EN" />
- <util:constant id="ja"
- static-field="me.arganzheng.study.spring.autowired.Constants.Language.JP" />
- <util:constant id="ind"
- static-field="me.arganzheng.study.spring.autowired.Constants.Language.IND" />
- <util:constant id="pt"
- static-field="me.arganzheng.study.spring.autowired.Constants.Language.PT" />
- <util:constant id="th"
- static-field="me.arganzheng.study.spring.autowired.Constants.Language.TH" />
- <util:constant id="ar"
- static-field="me.arganzheng.study.spring.autowired.Constants.Language.AR" />
- <util:constant id="en-rIn"
- static-field="me.arganzheng.study.spring.autowired.Constants.Language.EN_RIN" />
- <util:map id="languageChangesMap" key-type="java.lang.String"
- value-type="java.lang.String">
- <entry key="pt" value="pt" />
- <entry key="br" value="pt" />
- <entry key="jp" value="ja" />
- <entry key="ja" value="ja" />
- <entry key="ind" value="ind" />
- <entry key="id" value="ind" />
- <entry key="en-rin" value="en-rIn" />
- <entry key="in" value="en-rIn" />
- <entry key="en" value="en" />
- <entry key="gb" value="en" />
- <entry key="th" value="th" />
- <entry key="ar" value="ar" />
- <entry key="eg" value="ar" />
- </util:map>
- </beans>
其中static-field應(yīng)用的常量定義在如下類中:
- package me.arganzheng.study.spring.autowired;
- public interface Constants {
- public interface Language {
- public static final String EN = "CommonConstants.LANG_ENGLISH";
- public static final String JP = "CommonConstants.LANG_JAPANESE";
- public static final String IND = "CommonConstants.LANG_INDONESIAN";
- public static final String PT = "CommonConstants.LANG_PORTUGUESE";
- public static final String TH = "CommonConstants.LANG_THAI";
- public static final String EN_RIN = "CommonConstants.LANG_ENGLISH_INDIA";
- public static final String AR = "CommonConstants.LANG_Arabic";
- }
- }
然后如果我們在代碼中如下聲明依賴:
- public class AutowiredTest extends BaseSpringTestCase {
- @Autowired
- private Map<String, String> languageChangesMap;
- @Test
- public void testAutowired() {
- notNull(languageChangesMap);
- System.out.println(languageChangesMap.getClass().getSimpleName());
- System.out.println(languageChangesMap);
- }
- }
Guess what,詭異的事情發(fā)生了!
運(yùn)行結(jié)果如下:
- 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
- 嚴(yán)重: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@5c51ee0a] to prepare test instance [me.arganzheng.study.spring.autowired.AutowiredTest@6e301e0]
- 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)}
- ...
- 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)}
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843)
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
- at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
- ... 28 more
debug了一下,發(fā)現(xiàn)確實(shí)是Spring的一個(gè)bug。在DefaultListableBeanFactory的這個(gè)方法出問題了:
- protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName,
- Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
- ...
- else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
- Class<?> keyType = descriptor.getMapKeyType();
- if (keyType == null || !String.class.isAssignableFrom(keyType)) {
- if (descriptor.isRequired()) {
- throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +
- "] must be assignable to [java.lang.String]");
- }
- return null;
- }
- Class<?> valueType = descriptor.getMapValueType();
- if (valueType == null) {
- if (descriptor.isRequired()) {
- throw new FatalBeanException("No value type declared for map [" + type.getName() + "]");
- }
- return null;
- }
- Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor);
- if (matchingBeans.isEmpty()) {
- if (descriptor.isRequired()) {
- raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor);
- }
- return null;
- }
- if (autowiredBeanNames != null) {
- autowiredBeanNames.addAll(matchingBeans.keySet());
- }
- return matchingBeans;
- }
- ...
- }
關(guān)鍵在這一句:Map
- 嚴(yán)重: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@9476189] to prepare test instance [me.arganzheng.study.spring.autowired.AutowiredTest@2d546e21]
- ...
- 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)}
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843)
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
- at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
- ... 28 more
debug了一下,發(fā)現(xiàn)跟沒有指定qualifie name是一樣的執(zhí)行路徑。不是指定了bean name了嗎?為什么還是autowired by type呢?仔細(xì)查看了一下才發(fā)現(xiàn)。DefaultListableBeanFactory的doResolveDependency方法對首先對類型做 了區(qū)別:
- protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName,
- Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
- Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
- if (value != null) {
- if (value instanceof String) {
- String strVal = resolveEmbeddedValue((String) value);
- BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
- value = evaluateBeanDefinitionString(strVal, bd);
- }
- TypeConverter converter = (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, "array of " + componentType.getName(), descriptor);
- }
- return null;
- }
- if (autowiredBeanNames != null) {
- autowiredBeanNames.addAll(matchingBeans.keySet());
- }
- TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
- return converter.convertIfNecessary(matchingBeans.values(), type);
- }
- else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
- Class<?> elementType = descriptor.getCollectionType();
- if (elementType == null) {
- if (descriptor.isRequired()) {
- throw new FatalBeanException("No element type declared for collection [" + type.getName() + "]");
- }
- return null;
- }
- Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, descriptor);
- if (matchingBeans.isEmpty()) {
- if (descriptor.isRequired()) {
- raiseNoSuchBeanDefinitionException(elementType, "collection of " + elementType.getName(), descriptor);
- }
- return null;
- }
- if (autowiredBeanNames != null) {
- autowiredBeanNames.addAll(matchingBeans.keySet());
- }
- TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
- return converter.convertIfNecessary(matchingBeans.values(), type);
- }
- else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
- Class<?> keyType = descriptor.getMapKeyType();
- if (keyType == null || !String.class.isAssignableFrom(keyType)) {
- if (descriptor.isRequired()) {
- throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +
- "] must be assignable to [java.lang.String]");
- }
- return null;
- }
- Class<?> valueType = descriptor.getMapValueType();
- if (valueType == null) {
- if (descriptor.isRequired()) {
- throw new FatalBeanException("No value type declared for map [" + type.getName() + "]");
- }
- return null;
- }
- Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor);
- if (matchingBeans.isEmpty()) {
- if (descriptor.isRequired()) {
- raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor);
- }
- return null;
- }
- if (autowiredBeanNames != null) {
- autowiredBeanNames.addAll(matchingBeans.keySet());
- }
- return matchingBeans;
- }
- else {
- Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
- if (matchingBeans.isEmpty()) {
- if (descriptor.isRequired()) {
- raiseNoSuchBeanDefinitionException(type, "", descriptor);
- }
- return null;
- }
- if (matchingBeans.size() > 1) {
- String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor);
- if (primaryBeanName == null) {
- throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
- }
- if (autowiredBeanNames != null) {
- autowiredBeanNames.add(primaryBeanName);
- }
- return matchingBeans.get(primaryBeanName);
- }
- // We have exactly one match.
- Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
- if (autowiredBeanNames != null) {
- autowiredBeanNames.add(entry.getKey());
- }
- return entry.getValue();
- }
- }
如果是Array,Collection或者M(jìn)ap,則根據(jù)集合類中元素的類型來進(jìn)行autowired by type(Map使用value的類型)。為什么這么特殊處理呢?原來,Spring是為了達(dá)到這樣的目的:讓你可以一次注入所有符合類型的實(shí)現(xiàn),也就是 說可以這樣子注入:
- @Autowired
- private List<Car> cars;
如果你的car有多個(gè)實(shí)現(xiàn),那么都會注入進(jìn)來,不會再報(bào)
- org.springframework.beans.factory.NoSuchBeanDefinitionException:
- No unique bean of type [me.arganzheng.study.spring.autowired.Car] is defined:
- expected single matching bean but found 2: [audi, toyota].
- 然而,上面的情況如果你用@Resource則不會有這個(gè)問題:
- public class AutowiredTest extends BaseSpringTestCase {
- @Resource
- @Qualifier("languageChangesMap")
- private Map<String, String> languageChangesMap;
- @Test
- public void testAutowired() {
- assertNotNull(languageChangesMap);
- System.out.println(languageChangesMap.getClass().getSimpleName());
- System.out.println(languageChangesMap);
- }
- }
正常運(yùn)行:
- 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}
當(dāng)然,你如果不指定@Qualifier(“languageChangesMap”),同時(shí)field name不是languageChangesMap,那么還是一樣報(bào)錯的。
- 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=)}
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843)
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
- at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:438)
- at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:416)
- at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:550)
- at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150)
- at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
- at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:303)
- ... 26 more
而且,@Resource也可以實(shí)現(xiàn)上面的List接收所有實(shí)現(xiàn):
- public class AutowiredTest extends BaseSpringTestCase {
- @Resource
- @Qualifier("languageChangesMap")
- private Map<String, String> languageChangesMap;
- @Resource
- private List<Car> cars;
- @Test
- public void testAutowired() {
- assertNotNull(languageChangesMap);
- System.out.println(languageChangesMap.getClass().getSimpleName());
- System.out.println(languageChangesMap);
- assertNotNull(cars);
- System.out.println(cars.getClass().getSimpleName());
- System.out.println(cars);
- }
- }
運(yùn)行的妥妥的:
- 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]
這是因?yàn)锧Resource注解使用的是CommonAnnotationBeanPostProcessor處理器,跟 AutowiredAnnotationBeanPostProcessor不是同一個(gè)作者[/偷笑]。這里就不分析了,感興趣的同學(xué)可以自己看代碼研究 一下。
最終結(jié)論如下:
1、@Autowired和@Inject
autowired by type 可以 通過@Qualifier 顯式指定 autowired by qualifier name(非集合類。注意:不是autowired by bean name?。?br /> 如果 autowired by type 失?。ㄕ也坏交蛘哒业蕉鄠€(gè)實(shí)現(xiàn)),則退化為autowired by field name(非集合類)
2、@Resource
默認(rèn) autowired by field name
如果 autowired by field name失敗,會退化為 autowired by type
可以 通過@Qualifier 顯式指定 autowired by qualifier name
如果 autowired by qualifier name失敗,會退化為 autowired by field name。但是這時(shí)候如果 autowired by field name失敗,就不會再退化為autowired by type了
測試工程保存在GitHub上,是標(biāo)準(zhǔn)的maven工程,感興趣的同學(xué)可以clone到本地運(yùn)行測試一下。
補(bǔ)充
有同事指出Spring官方文檔上有這么一句話跟我的結(jié)有點(diǎn)沖突:
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注解,其實(shí)也是autowired by type。@Qualifier只是一個(gè)限定詞,過濾條件而已。重新跟進(jìn)了一下代碼,發(fā)現(xiàn)確實(shí)是這樣子的。Spring設(shè)計(jì)的這個(gè) @Qualifier name 并不等同于 bean name。他有點(diǎn)類似于一個(gè)tag。不過如果這個(gè)tag是***的化,那么其實(shí)效果上等同于bean name。實(shí)現(xiàn)上,Spring是先getByType,得到list candicates,然后再根據(jù)qualifier name進(jìn)行過濾。
再定義一個(gè)蘭博基尼,這里使用@Qualifier指定:
- package me.arganzheng.study.spring.autowired;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.stereotype.Component;
- @Component
- @Qualifier("luxury")
- public class Lamborghini implements Car {
- }
再定義一個(gè)勞斯萊斯,這里故意用@Named指定:
- package me.arganzheng.study.spring.autowired;
- import javax.inject.Named;
- import org.springframework.stereotype.Component;
- @Component
- @Named("luxury")
- public class RollsRoyce implements Car {
- }
測試一下注入定義的豪華車:
- package me.arganzheng.study.spring.autowired;
- import static junit.framework.Assert.assertNotNull;
- import java.util.List;
- import me.arganzheng.study.BaseSpringTestCase;
- import org.junit.Test;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Qualifier;
- /**
- *
- * @author zhengzhibin
- *
- */
- public class AutowiredTest extends BaseSpringTestCase {
- @Autowired
- @Qualifier("luxury")
- private List<Car> luxuryCars;
- @Test
- public void testAutowired() {
- assertNotNull(luxuryCars);
- System.out.println(luxuryCars.getClass().getSimpleName());
- System.out.println(luxuryCars);
- }
- }
運(yùn)行結(jié)果如下:
- ArrayList
- [me.arganzheng.study.spring.autowired.Lamborghini@66b875e1, me.arganzheng.study.spring.autowired.RollsRoyce@58433b76]
補(bǔ)充:Autowiring modes
Spring支持四種autowire模式,當(dāng)使用XML配置方式時(shí),你可以通過autowire屬性指定。
- 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.
- 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.
- 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.
- 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注解的時(shí)候,則稍微復(fù)雜一些,會有一個(gè)失敗退化過程,并且引入了Qualifier。不過基本原理是一樣。