JavaSpring中各依賴注入注解的區(qū)別是什么

本篇文章給大家分享的是有關Java Spring中各依賴注入注解的區(qū)別是什么,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

公司主營業(yè)務:網站制作、成都網站設計、移動網站開發(fā)等業(yè)務。幫助企業(yè)客戶真正實現互聯網宣傳,提高企業(yè)的競爭能力。成都創(chuàng)新互聯是一支青春激揚、勤奮敬業(yè)、活力青春激揚、勤奮敬業(yè)、活力澎湃、和諧高效的團隊。公司秉承以“開放、自由、嚴謹、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領域給我們帶來的挑戰(zhàn),讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。成都創(chuàng)新互聯推出彝良免費做網站回饋大家。

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提供的注解,其他幾個都是JDK本身內建的注解,Spring對這些注解也進行了支持。但是使用起來這三者到底有什么區(qū)別呢?筆者經過方法的測試,發(fā)現一些有意思的特性。

區(qū)別總結如下:

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

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

@Autowired和@Inject - 默認 autowired by type - 可以 通過@Qualifier 顯式指定 autowired by qualifier name。 - 如果 autowired by type 失?。ㄕ也坏交蛘哒业蕉鄠€實現),則退化為autowired by field name  @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了。

TIPS Qualified name VS Bean name

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

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

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

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應用的常量定義在如下類中:

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ā)生了!

運行結果如下:

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

嚴重: 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ā)現確實是Spring的一個bug。在DefaultListableBeanFactory的這個方法出問題了:

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;         }         ...     }

關鍵在這一句:Map

嚴重: 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ā)現跟沒有指定qualifie name是一樣的執(zhí)行路徑。不是指定了bean name了嗎?為什么還是autowired  by  type呢?仔細查看了一下才發(fā)現。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或者Map,則根據集合類中元素的類型來進行autowired by  type(Map使用value的類型)。為什么這么特殊處理呢?原來,Spring是為了達到這樣的目的:讓你可以一次注入所有符合類型的實現,也就是 說可以這樣子注入:

@Autowired private List<Car> cars;

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

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則不會有這個問題:  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);     } }

正常運行:

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(“l(fā)anguageChangesMap”),同時field name不是languageChangesMap,那么還是一樣報錯的。

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也可以實現上面的List接收所有實現:

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);     } }

運行的妥妥的:

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

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只是一個限定詞,過濾條件而已。重新跟進了一下代碼,發(fā)現確實是這樣子的。Spring設計的這個 @Qualifier  name 并不等同于 bean name。他有點類似于一個tag。不過如果這個tag是***的化,那么其實效果上等同于bean  name。實現上,Spring是先getByType,得到list candicates,然后再根據qualifier name進行過濾。

再定義一個蘭博基尼,這里使用@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 {  }

再定義一個勞斯萊斯,這里故意用@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);     }  }

運行結果如下:

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

補充:Autowiring modes

Spring支持四種autowire模式,當使用XML配置方式時,你可以通過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.

以上就是Java Spring中各依賴注入注解的區(qū)別是什么,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注創(chuàng)新互聯行業(yè)資訊頻道。

新聞名稱:JavaSpring中各依賴注入注解的區(qū)別是什么
本文路徑:http://muchs.cn/article6/ihidig.html

成都網站建設公司_創(chuàng)新互聯,為您提供云服務器定制網站、網站營銷小程序開發(fā)、手機網站建設、品牌網站制作

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯

外貿網站建設