> Java > java지도 시간 > 본문

Java Spring의 다양한 종속성 주입 주석 간의 차이점에 대한 자세한 설명

高洛峰
풀어 주다: 2017-01-23 10:56:26
원래의
1335명이 탐색했습니다.

Annotation 주입은 이름에서 알 수 있듯이 Annotation을 통해 주입을 수행하는 것입니다. Spring 및 주입과 관련된 일반적인 주석에는 Autowired, Resource, Qualifier, Service, Controller, Repository 및 Component가 있습니다.

Autowired는 자동 주입으로, 주입할 스프링 컨텍스트에서 적절한 Bean을 자동으로 찾습니다.

리소스는 주입할 이름을 지정하는 데 사용됩니다.

한정자 Autowired 협력을 사용하여 클래스를 서비스 계층 클래스, 컨트롤러 계층 클래스 및 데이터 저장 계층 클래스로 각각 표시하려면 빈
서비스, 컨트롤러, 저장소의 이름을 지정합니다. 스프링이 주석 구성을 스캔하면 이를 표시합니다. 빈을 생성하는 클래스.

Component는 일반적인 용어입니다. 표시된 클래스는 Spring이 주석 구성을 스캔할 때 이러한 클래스를 표시하여 Bean을 생성합니다.

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에서 제공하는 주석이고 다른 것들도 Spring에서 내장된 주석을 지원합니다. JDK 자체의 주석에 있습니다. 그런데 이 세 가지의 사용상의 차이점은 무엇입니까? 저자는 방법을 테스트한 후 몇 가지 흥미로운 특징을 발견했습니다.

차이점을 요약하면 다음과 같습니다.

1. @Autowired에는 false로 구성할 수 있는 필수 속성이 있습니다. 이 경우 해당 Bean을 찾을 수 없으면 예외가 발생합니다. 던져지지 마십시오. @Inject 및 @Resource는 해당 구성을 제공하지 않으므로 이를 찾아야 합니다. 그렇지 않으면 예외가 발생합니다.

2. @Autowired와 @Inject는 둘 다 AutowiredAnnotationBeanPostProcessor를 사용하여 종속성 주입을 처리하기 때문에 기본적으로 동일합니다. 그러나 @Resource는 예외이며 CommonAnnotationBeanPostProcessor를 사용하여 종속성 주입을 처리합니다. 물론 둘 다 BeanPostProcessors입니다.

@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 정규명 VS Bean 이름

Spring 디자인에서 정규명은 Bean 이름과 동일하지 않습니다. 후자는 고유해야 하지만 전자는 유사합니다. 태그나 그룹의 기능은 특정 빈을 분류하는 것입니다. getByTag(group)의 효과를 얻을 수 있습니다. XML로 구성된 Bean의 경우 id 속성을 통해 Bean 이름을 지정할 수 있으며(지정하지 않은 경우 클래스 이름의 첫 글자는 기본적으로 소문자임) 레이블을 통해 한정자 이름을 지정할 수 있습니다:

<bean id="lamborghini" class="me.arganzheng.study.spring.autowired.Lamborghini">
<qualifier value="luxury"/>
<!-- inject any dependencies required by this bean -->
</bean>
로그인 후 복사

주석 메서드를 사용하는 경우 @Qualifier 주석을 통해 한정자 이름을 지정하고 @Named 또는 @Component(@Service, @Repository 등) 값을 통해 Bean 이름을 지정할 수 있습니다.

@Component("lamborghini")
@Qualifier("luxury")
public class Lamborghini implements Car {
}
로그인 후 복사

또는

@Component
@Named("lamborghini")
@Qualifier("luxury")
public class Lamborghini implements Car {
}
로그인 후 복사

마찬가지로 빈 이름이 지정되지 않으면 Spring은 기본적으로 클래스 이름의 첫 글자를 소문자로 설정합니다(Lamborghini =>람보르기니).

3. XML 주입 전에 Annotation을 통해 종속성을 주입합니다. 두 주입 방법이 동일한 Bean에 대한 종속성에 사용되는 경우 XML 주입 방법이 우선합니다. 그러나 XML로 구성된 Bean에는 Anotation을 통해 주입된 종속성을 주입할 수 없다고 걱정할 필요는 없습니다.

4. 현재 유형별 자동 연결 방식(저자는 3.2.3.RELEASE 버전을 사용 중임), Spring의 AutowiredAnnotationBeanPostProcessor 구현에는 모두 "버그"가 있습니다. 즉, @Autowired와 @Inject 모두 "버그"가 있습니다. 버그" 버그입니다(고의적인 것 같아서 버그가 아니라 버그라고 부르는데...). 이는 온라인에서 발생한 버그이며, 이 글을 작성하게 된 이유이기도 합니다. 장면은 다음과 같습니다.

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);
}
}
로그인 후 복사

뭔 일인지 맞춰보세요. 뭔가 이상한 일이 일어났습니다!

실행 결과는 다음과 같습니다.

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

심각: 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 &#39;me.arganzheng.study.spring.autowired.AutowiredTest&#39;: 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
로그인 후 복사

디버그해 보니 확실히 Spring 버그인 걸 발견했습니다. 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

Serious: 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
로그인 후 복사

디버깅해보니 한정자 이름을 지정하지 않은 것처럼 실행 경로가 동일한 것을 발견했습니다. Bean 이름이 지정되어 있지 않습니까? 왜 여전히 유형별로 자동 연결되어 있나요? 자세히 살펴본 후 발견했습니다. DefaultListableBeanFactory의 doResolveDependency 메소드는 먼저 유형을 구별합니다:

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인 경우 컬렉션 클래스의 요소 유형에 따라 유형별로 자동 연결됩니다(Map은 값 유형). 왜 그렇게 특별하게 취급됩니까? Spring은 이 목적을 달성하도록 설계되었습니다. 즉, 유형과 일치하는 모든 구현을 한 번에 주입할 수 있도록 허용합니다. 이는 다음과 같이 주입할 수 있음을 의미합니다.

@Autowired

private List cars;

자동차에 여러 구현이 있는 경우 모두 주입되고 다시 보고되지 않습니다

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("언어ChangesMap)를 지정하지 않으면 ") 필드 이름이 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는 위의 목록을 구현하여 모든 구현을 수신할 수도 있습니다.

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!)

如果 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指定:

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.
로그인 후 복사

如果使用@Autowired、@Inject或者@Resource注解的时候,则稍微复杂一些,会有一个失败退化过程,并且引入了Qualifier。不过基本原理是一样。

更多详解Java Spring各种依赖注入注解的区别相关文章请关注PHP中文网!


관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!