1. 程式人生 > >Spring框架參考手冊_5.0.0_中英文對照版_Part II_3.9

Spring框架參考手冊_5.0.0_中英文對照版_Part II_3.9

文章作者:Tyan
部落格:noahsnail.com  |  CSDN  |  簡書

3.9 Annotation-based container configuration

Are annotations better than XML for configuring Spring?

The introduction of annotation-based configurations raised the question of whether this approach is ‘better’ than XML. The short answer is it depends. The long answer is that each approach has its pros and cons, and usually it is up to the developer to decide which strategy suits them better. Due to the way they are defined, annotations provide a lot of context in their declaration, leading to shorter and more concise configuration. However, XML excels at wiring up components without touching their source code or recompiling them. Some developers prefer having the wiring close to the source while others argue that annotated classes are no longer POJOs and, furthermore, that the configuration becomes decentralized and harder to control.

No matter the choice, Spring can accommodate both styles and even mix them together. It’s worth pointing out that through its JavaConfig option, Spring allows annotations to be used in a non-invasive way, without touching the target components source code and that in terms of tooling, all configuration styles are supported by the Spring Tool Suite.

在配置Spring時註解是否比XML更好?

基於註解配置的引入引出了一個問題——這種方式是否比基於XML的配置更好。簡短的回答是視情況而定。長一點的回答是每種方法都有它的優點和缺點,通常是由開發者決定哪一種策略更適合他們。由於註解的定義方式,註解在它們的宣告中提供了許多上下文,導致配置更簡短更簡潔。然而,XML擅長連線元件而不必接觸原始碼或重新編譯它們。一些開發者更喜歡接近原始碼,而另一些人則認為基於註解的類不再是POJOs,此外,配置變的去中心化,而且更難控制。

無論選擇是什麼,Spring都能容納這兩種風格,甚至可以將它們混合在一起。值得指出的是,通過它的Java配置選項,Spring允許註解以一種非入侵的方式使用,不觸碰目標元件原始碼和那些工具,所有的配置風格由Spring工具套件支援。

An alternative to XML setups is provided by annotation-based configuration which rely on the bytecode metadata for wiring up components instead of angle-bracket declarations. Instead of using XML to describe a bean wiring, the developer moves the configuration into the component class itself by using annotations on the relevant class, method, or field declaration. As mentioned in the section called “Example: The RequiredAnnotationBeanPostProcessor”, using a BeanPostProcessor in conjunction with annotations is a common means of extending the Spring IoC container. For example, Spring 2.0 introduced the possibility of enforcing required properties with the @Required annotation. Spring 2.5 made it possible to follow that same general approach to drive Spring’s dependency injection. Essentially, the @Autowired annotation provides the same capabilities as described in Section 3.4.5, “Autowiring collaborators” but with more fine-grained control and wider applicability. Spring 2.5 also added support for JSR-250 annotations such as @PostConstruct, and @PreDestroy. Spring 3.0 added support for JSR-330 (Dependency Injection for Java) annotations contained in the javax.inject package such as @Inject and @Named. Details about those annotations can be found in the relevant section.

基於註解的配置提供了一種XML設定的可替代方式,它依賴於位元組碼元資料來組裝元件,而不是用尖括號宣告的方式。代替使用XML來描述bean組裝,開發者通過將註解使用在相關的類,方法或欄位宣告中,將配置移動到了元件類本身的內部。正如在“Example: The RequiredAnnotationBeanPostProcessor”那節提到的那樣,使用BeanPostProcessor與註解結合是擴充套件Spring IoC容器的的常見方法。例如,Spring 2.0引入了@Required註解來執行需要的屬性的可能性。Spring 2.5使以同樣地通用方法來驅動Spring的依賴注入變為可能。本質上來說,@Autowired提供瞭如3.4.5小節描述的同樣的能力。“Autowiring collaborators”但更細粒度的控制和更廣的應用性。Spring 2.5也新增對JSR-250註解的支援,例如,@PostConstruct@PreDestroy
。Spring 3.0添加了對JSR-330,包含在javax.inject包內的註解(Java的依賴注入)的支援,例如@Inject@Named。關於這些註解的細節可以在相關的小節找到。

Annotation injection is performed before XML injection, thus the latter configuration will override the former for properties wired through both approaches.

註解注入在XML注入之前進行,因此對於通過兩種方法進行組裝的屬性後者的配置會覆蓋前者。

As always, you can register them as individual bean definitions, but they can also be implicitly registered by including the following tag in an XML-based Spring configuration (notice the inclusion of the context namespace):

跟以前一樣,你可以作為單獨的bean定義來註冊它們,但也可以通過在一個基於XML的Spring配置(注入包含上下文名稱空間)中包含下面的標籤來隱式的註冊它們:

<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

(The implicitly registered post-processors include AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor, as well as the aforementioned RequiredAnnotationBeanPostProcessor.)

(隱式註冊的後處理器包括 AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessorPersistenceAnnotationBeanPostProcessor和前面提到的RequiredAnnotationBeanPostProcessor。)

<context:annotation-config/> only looks for annotations on beans in the same application context in which it is defined. This means that, if you put <context:annotation-config/> in a WebApplicationContext for a DispatcherServlet, it only checks for @Autowired beans in your controllers, and not your services. See Section 18.2, “The DispatcherServlet” for more information.

<context:annotation-config/>僅在定義它的同樣的應用上下文中尋找註解的beans。這意味著,如果你在一個為DispatcherServlet服務的WebApplicationContext中放置了<context:annotation-config/>,它只能在你的控制器中尋找@Autowired註解的beans,而不是在你的服務層中。更多資訊請看18.2小節,“The DispatcherServlet”。

3.9.1 @Required

The @Required annotation applies to bean property setter methods, as in the following example:

@Required註解應用到bean屬性的setter方法上,例子如下:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Required
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...

}

This annotation simply indicates that the affected bean property must be populated at configuration time, through an explicit property value in a bean definition or through autowiring. The container throws an exception if the affected bean property has not been populated; this allows for eager and explicit failure, avoiding NullPointerExceptions or the like later on. It is still recommended that you put assertions into the bean class itself, for example, into an init method. Doing so enforces those required references and values even when you use the class outside of a container.

這個註解僅僅是表明受影響的bean屬性必須在配置時通過顯式的bean定義或自動組裝填充。如果受影響的bean屬性沒有填充,容器會丟擲一個異常,這允許及早明確的失敗,避免NullPointerExceptions或後面出現類似的情況。仍然建議你在bean類本身加入斷言,例如,加入到初始化方法中。這樣做可以強制這些需要的引用和值,甚至是你在容器外部使用這個類的時候。

3.9.2 @Autowired

JSR 330’s @Inject annotation can be used in place of Spring’s @Autowired annotation in the examples below. See here for more details.

在下面的例子中JSR 330的@Inject註解可以用來代替Spring的@Autowired註解。

You can apply the @Autowired annotation to constructors:

你可以將@Autowired註解應用到建構函式上。

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...

}

As of Spring Framework 4.3, the @Autowired constructor is no longer necessary if the target bean only defines one constructor. If several constructors are available, at least one must be annotated to teach the container which one it has to use.

從Spring框架4.3起,如果目標bena僅定義了一個建構函式,那麼@Autowired註解的建構函式不再是必要的。如果一些建構函式是可獲得的,至少有一個必須要加上註解,以便於告訴容器使用哪一個。

As expected, you can also apply the @Autowired annotation to “traditional” setter methods:

正如預料的那樣,你也可以將@Autowired註解應用到“傳統的”setter方法上:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...

}

You can also apply the annotation to methods with arbitrary names and/or multiple arguments:

你也可以應用註解到具有任何名字和/或多個引數的方法上:

public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...

}

You can apply @Autowired to fields as well and even mix it with constructors:

你也可以應用@Autowired到欄位上,甚至可以與建構函式混合用:

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    private MovieCatalog movieCatalog;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...

}

It is also possible to provide all beans of a particular type from the ApplicationContext by adding the annotation to a field or method that expects an array of that type:

通過給帶有陣列的欄位或方法新增@Autowired註解,也可以從ApplicationContext中提供一組特定型別的bean:

public class MovieRecommender {

    @Autowired
    private MovieCatalog[] movieCatalogs;

    // ...

}

The same applies for typed collections:

同樣也可以應用到具有同一型別的集合上:

public class MovieRecommender {

    private Set<MovieCatalog> movieCatalogs;

    @Autowired
    public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
        this.movieCatalogs = movieCatalogs;
    }

    // ...

}

Your beans can implement the org.springframework.core.Ordered interface or either use the @Order or standard @Priority annotation if you want items in the array or list to be sorted into a specific order.

如果你希望陣列或列表中的項按指定順序排序,你的bean可以實現org.springframework.core.Ordered介面,或使用@Order或標準@Priority註解。

Even typed Maps can be autowired as long as the expected key type is String. The Map values will contain all beans of the expected type, and the keys will contain the corresponding bean names:

只要期望的key是String,那麼型別化的Maps就可以自動組裝。Map的值將包含所有期望型別的beans,key將包含對應的bean名字:

public class MovieRecommender {

    private Map<String, MovieCatalog> movieCatalogs;

    @Autowired
    public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
        this.movieCatalogs = movieCatalogs;
    }

    // ...

}

By default, the autowiring fails whenever zero candidate beans are available; the default behavior is to treat annotated methods, constructors, and fields as indicating required dependencies. This behavior can be changed as demonstrated below.

預設情況下,當沒有候選beans可獲得時,自動組裝會失敗;預設的行為是將註解的方法,建構函式和欄位看作指明瞭需要的依賴。這個行為也可以通過下面的方式去改變。

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired(required=false)
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...

}

Only one annotated constructor per-class can be marked as required, but multiple non-required constructors can be annotated. In that case, each is considered among the candidates and Spring uses the greediest constructor whose dependencies can be satisfied, that is the constructor that has the largest number of arguments.

@Autowired’s required attribute is recommended over the @Required annotation. The required attribute indicates that the property is not required for autowiring purposes, the property is ignored if it cannot be autowired. @Required, on the other hand, is stronger in that it enforces the property that was set by any means supported by the container. If no value is injected, a corresponding exception is raised.

每個類只有一個建構函式可以標記為必需的,但可以註解多個非必需的建構函式。在這種情況下,會考慮這些候選者中的每一個,Spring使用最貪婪的建構函式,即依賴最滿足的建構函式,具有最大數目的引數。

建議在@Required註解之上使用@Autowiredrequired特性。required特性表明這個屬性自動裝配是不需要的,如果這個屬性不能被自動裝配,它會被忽略。另一方面@Required是更強大的,在它強制這個屬性被任何容器支援的bean設定。如果沒有值注入,會丟擲對應的異常。

You can also use @Autowired for interfaces that are well-known resolvable dependencies: BeanFactory, ApplicationContext, Environment, ResourceLoader, ApplicationEventPublisher, and MessageSource. These interfaces and their extended interfaces, such as ConfigurableApplicationContext or ResourcePatternResolver, are automatically resolved, with no special setup necessary.

你也可以對那些已知的具有可解析依賴的介面使用@AutowiredBeanFactoryApplicationContextEnvironment, ResourceLoaderApplicationEventPublisherMessageSource。這些介面和它們的擴充套件介面,例如ConfigurableApplicationContextResourcePatternResolver,可以自動解析,不需要特別的設定。

public class MovieRecommender {

    @Autowired
    private ApplicationContext context;

    public MovieRecommender() {
    }

    // ...

}

@Autowired, @Inject, @Resource, and @Value annotations are handled by Spring BeanPostProcessor implementations which in turn means that you cannot apply these annotations within your own BeanPostProcessor or BeanFactoryPostProcessor types (if any). These types must be ‘wired up’ explicitly via XML or using a Spring @Bean method.

@Autowired@Inject@Resource@Value註解是通過Spring BeanPostProcessor實現處理,這反過來意味著你不能在你自己的BeanPostProcessorBeanFactoryPostProcessor中應用這些註解(如果有的話)。這些型別必須顯式的通過XML或使用Spring的@Bean方法來’wired up’。

3.9.3 Fine-tuning annotation-based autowiring with @Primary

Because autowiring by type may lead to multiple candidates, it is often necessary to have more control over the selection process. One way to accomplish this is with Spring’s @Primary annotation. @Primary indicates that a particular bean should be given preference when multiple beans are candidates to be autowired to a single-valued dependency. If exactly one ‘primary’ bean exists among the candidates, it will be the autowired value.

因為根據型別的自動裝配可能會導致多個候選目標,所以在選擇過程中進行更多的控制經常是有必要的。一種方式通過Spring的@Primary註解來完成。當有個多個候選bean要組裝到一個單值的依賴時,@Primary表明指定的bean應該具有更高的優先順序。如果確定一個’primary’ bean位於候選目標中間,它將是那個自動裝配的值。

Let’s assume we have the following configuration that defines firstMovieCatalog as the primary MovieCatalog.

假設我們具有如下配置,將firstMovieCatalog定義為主要的MovieCatalog

@Configuration
public class MovieConfiguration {

    @Bean
    @Primary
    public MovieCatalog firstMovieCatalog() { ... }

    @Bean
    public MovieCatalog secondMovieCatalog() { ... }

    // ...

}

With such configuration, the following MovieRecommender will be autowired with the firstMovieCatalog.

根據這樣的配置,下面的MovieRecommender將用firstMovieCatalog進行自動裝配。

public class MovieRecommender {

    @Autowired
    private MovieCatalog movieCatalog;

    // ...

}

The corresponding bean definitions appear as follows.

對應的bean定義如下:

<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog" primary="true">
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

3.9.4 Fine-tuning annotation-based autowiring with qualifiers

@Primary is an effective way to use autowiring by type with several instances when one primary candidate can be determined. When more control over the selection process is required, Spring’s @Qualifier annotation can be used. You can associate qualifier values with specific arguments, narrowing the set of type matches so that a specific bean is chosen for each argument. In the simplest case, this can be a plain descriptive value:

當有多個例項需要確定一個主要的候選物件時,@Primary是一種按型別自動裝配的有效方式。當需要在選擇過程中進行更多的控制時,可以使用Spring的@Qualifier註解。為了給每個選擇一個特定的bean,你可以將限定符的值與特定的引數聯絡在一起,減少型別匹配集合。在最簡單的情況下,這是一個純描述性值:

public class MovieRecommender {

    @Autowired
    @Qualifier("main")
    private MovieCatalog movieCatalog;

    // ...

}

The @Qualifier annotation can also be specified on individual constructor arguments or method parameters:

@Qualifier註解也可以指定單個建構函式引數或方法引數:

public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(@Qualifier("main")MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...

}

The corresponding bean definitions appear as follows. The bean with qualifier value “main” is wired with the constructor argument that is qualified with the same value.

對應的bean定義如下。限定符值為”main”的bean被組裝到有相同值的建構函式引數中。

<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="main"/>

        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="action"/>

        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

For a fallback match, the bean name is considered a default qualifier value. Thus you can define the bean with an id “main” instead of the nested qualifier element, leading to the same matching result. 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. Good qualifier values are “main” or “EMEA” or “persistent”, expressing characteristics of a specific component that are independent from the bean id, which may be auto-generated in case of an anonymous bean definition like the one in the preceding example.

對於回退匹配,bean名字被認為是預設的限定符值。因此你可以定義一個id為main的bean來代替內嵌的限定符元素,會有同樣的匹配結果。然而,儘管你可以使用這個約定根據名字引用特定的beans,但是@Autowired從根本上來講是使用可選的語義限定符來進行型別驅動注入的。這意味著限定符的值,即使回退到bean名稱,總是縮小語義型別匹配的集合;它們沒有從語義上將一個引用表達為一個唯一的bean id。好的限定符值是”main”或”EMEA”或”persistent”,表達一個特定元件的性質,這個元件是獨立於bean id的,即使前面例子中像這個bean一樣的匿名bean會自動生成id。

Qualifiers also apply to typed collections, as discussed above, for example, to Set<MovieCatalog>. In this case, all matching beans according to the declared qualifiers are injected as a collection. This implies that qualifiers do not have to be unique; they rather simply constitute filtering criteria. For example, you can define multiple MovieCatalog beans with the same qualifier value “action”, all of which would be injected into a Set<MovieCatalog> annotated with @Qualifier("action").

正如前面討論的那樣,限定符也可以應用到型別結合上,例如,Set<MovieCatalog>。在這個例子中,根據宣告的限定符匹配的所有beans作為一個集合進行注入。這意味著限定符不必是唯一的;它們只是構成過濾標準。例如,你可以定義多個具有同樣限定符值”action”的MovieCatalog,所有的這些都將注入到帶有註解@Qualifier("action")Set<MovieCatalog>中。

If you intend to express annotation-driven injection by name, do not primarily use @Autowired, even if is technically capable of referring to a bean name through @Qualifier values. Instead, use the JSR-250 @Resource annotation, which is semantically defined to identify a specific target component by its unique name, with the declared type being irrelevant for the matching process. @Autowired has rather different semantics: After selecting candidate beans by type, the specified String qualifier value will be considered within those type-selected candidates only, e.g. matching an “account” qualifier against beans marked with the same qualifier label.

For beans that are themselves defined as a collection/map or array type, @Resource is a fine solution, referring to the specific collection or array bean by unique name. That said, as of 4.3, collection/map and array types can be matched through Spring’s @Autowired type matching algorithm as well, as long as the element type information is preserved in @Bean return type signatures or collection inheritance hierarchies. In this case, qualifier values can be used to select among same-typed collections, as outlined in the previous paragraph.

As of 4.3, @Autowired also considers self references for injection, i.e. references back to the bean that is currently injected. Note that self injection is a fallback; regular dependencies on other components always have precedence. In that sense, self references do not participate in regular candidate selection and are therefore in particular never primary; on the contrary, they always end up as lowest precedence. In practice, use self references as a last resort only, e.g. for calling other methods on the same instance through the bean’s transactional proxy: Consider factoring out the affected methods to a separate delegate bean in such a scenario. Alternatively, use @Resource which may obtain a proxy back to the current bean by its unique name.

@Autowired applies to fields, constructors, and multi-argument methods, allowing for narrowing through qualifier annotations at the parameter level. By contrast, @Resource is supported only for fields and bean property setter methods with a single argument. As a consequence, stick with qualifiers if your injection target is a constructor or a multi-argument method.

@Autowired可以應用到欄位,建構函式和多引數方法上,允許通過限定符註解在引數層面上縮減候選目標。相比之下,@Resource僅支援欄位和bean屬性的帶有單個引數的setter方法。因此,如果你的注入目標是一個建構函式或一個多引數的方法,堅持使用限定符。

如果你想通過名字表達註解驅動的注入,不要主要使用@Autowired,雖然在技術上能通過@Qualifier值引用一個bean名字。作為可替代產品,可以使用JSR-250 @Resource註解,它在語義上被定義為通過元件唯一的名字來識別特定的目標元件,宣告的型別與匹配過程無關。@Autowired有不同的語義:通過型別選擇候選beans,特定的String限定符值被認為只在型別選擇的候選目標中,例如,在那些標記為具有相同限定符標籤的beans中匹配一個”account”限定符。

對於那些本身定義在集合/對映或陣列型別中的beans來說,@Resource是一個很好的解決方案,適用於特定的集合或通過唯一名字區分的陣列bean。也就是說,自Spring 4.3起,集合/對映和陣列型別中也可以通過Spring的@Autowired型別匹配演算法進行匹配,只要元素型別資訊在@Bean中保留,返回型別簽名或集合繼承體系。在這種情況下,限定符值可以用來在相同型別的集合中選擇,正如在前一段中概括的那樣。

自Spring 4.3起,@Autowired也考慮自引用注入,例如,引用返回當前注入的bean。注意自注入是備用;普通對其它元件的依賴關係總是優先的。在這個意義上,自引用不參與普通的候選目標選擇,因此尤其是從不是主要的;恰恰相反,它們最終總是最低的優先順序。在實踐中,自引用只是作為最後的手段,例如,通過bean的事務代理呼叫同一例項的其它方法:在考慮抽出受影響的方法來分隔代理bean的場景中。或者,使用@Resource通過它的唯一名字可能得到一個返回當前bean的代理。

@Autowired可以應用到欄位,建構函式和多引數方法上,允許通過限定符註解在引數層面上縮減候選目標。相比之下,@Resource僅支援欄位和bean屬性的帶有單個引數的setter方法。因此,如果你的注入目標是一個建構函式或一個多引數的方法,堅持使用限定符。

You can create your own custom qualifier annotations. Simply define an annotation and provide the @Qualifier annotation within your definition:

你可以建立自己的定製限定符註解。簡單定義一個註解,在你自己的定義中提供@Qualifier註解:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {

    String value();
}

Then you can provide the custom qualifier on autowired fields and parameters:

然後你可以在自動裝配的欄位和引數上提供定製的限定符:

public class MovieRecommender {

    @Autowired
    @Genre("Action")
    private MovieCatalog actionCatalog;
    private MovieCatalog comedyCatalog;

    @Autowired
    public void setComedyCatalog(@Genre("Comedy") MovieCatalog comedyCatalog) {
        this.comedyCatalog = comedyCatalog;
    }

    // ...

}

Next, provide the information for the candidate bean definitions. You can add <qualifier/> tags as sub-elements of the <bean/> tag and then specify the type and value to match your custom qualifier annotations. The type is matched against the fully-qualified class name of the annotation. Or, as a convenience if no risk of conflicting names exists, you can use the short class name. Both approaches are demonstrated in the following example.

接下來,提供候選bean定義的資訊。你可以新增<qualifier/>標記作為<bean/>標記的子元素,然後指定匹配你的定製限定符註解的型別和值。型別用來匹配註解的全限定類名稱。或者,如果沒有名稱衝突的風險,為了方便,你可以使用簡寫的類名稱。下面的例子證實了這些方法。

<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="Genre" value="Action"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="example.Genre" value="Comedy"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

In Section 3.10, “Classpath scanning and managed components”, you will see an annotation-based alternative to providing the qualifier metadata in XML. Specifically, see Section 3.10.8, “Providing qualifier metadata with annotations”.

在3.10小節,“類路徑掃描和管理元件”中,你將看到一個基於註解的替代方法,在XML中提供限定符元資料。特別地,看3.10.8小節,“用註解提供限定符元資料”。

In some cases, it may be sufficient to use an annotation without a value. This may be useful when the annotation serves a more generic purpose and can be applied across several different types of dependencies. For example, you may provide an offline catalog that would be searched when no Internet connection is available. First define the simple annotation:

在某些情況下,使用沒有值的註解就是足夠的。當註解為了通用的目的時,這是非常有用的,可以應用到跨幾個不同型別的依賴上。例如,當網路不可用時,你可以提供一個要搜尋的離線目錄。首先定義一個簡單的註解:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {

}

Then add the annotation to the field or property to be autowired:

然後將註解新增到要自動裝配的欄位或屬性上:

public class MovieRecommender {

    @Autowired
    @Offline
    private MovieCatalog offlineCatalog;

    // ...

}

Now the bean definition only needs a qualifier type:

現在bean定義只需要一個限定符型別:

<bean class="example.SimpleMovieCatalog">
    <qualifier type="Offline"/>
    <!-- inject any dependencies required by this bean -->
</bean>

You can also define custom qualifier annotations that accept named attributes in addition to or instead of the simple value attribute. If multiple attribute values are then specified on a field or parameter to be autowired, a bean definition must match all such attribute values to be considered an autowire candidate. As an example, consider the following annotation definition:

你也可以定義接收命名屬性之外的定製限定符註解或代替簡單的值屬性。如果要注入的欄位或引數指定了多個屬性值,bean定義必須匹配所有的屬性值才會被認為是一個可自動裝配的候選目標。作為一個例子,考慮下面的註解定義:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {

    String genre();

    Format format();

}

In this case Format is an enum:

這種情況下Format是列舉型別:

public enum Format {
    VHS, DVD, BLURAY
}

The fields to be autowired are annotated with the custom qualifier and include values for both attributes: genre and format.

要自動裝配的欄位使用定製限定符進行註解,並且包含了兩個屬性值:genreformat

public class MovieRecommender {

    @Autowired
    @MovieQualifier(format=Format.VHS, genre="Action")
    private MovieCatalog actionVhsCatalog;

    @Autowired
    @MovieQualifier(format=Format.VHS, genre="Comedy")
    private MovieCatalog comedyVhsCatalog;

    @Autowired
    @MovieQualifier(format=Format.DVD, genre="Action")
    private MovieCatalog actionDvdCatalog;

    @Autowired
    @MovieQualifier(format=Format.BLURAY, genre="Comedy")
    private MovieCatalog comedyBluRayCatalog;

    // ...

}

Finally, the bean definitions should contain matching qualifier values. This example also demonstrates that bean meta attributes may be used instead of the <qualifier/> sub-elements. If available, the <qualifier/> and its attributes take precedence, but the autowiring mechanism falls back on the values provided within the <meta/> tags if no such qualifier is present, as in the last two bean definitions in the following example.

最後,bean定義應該包含匹配的限定符值。這個例子也證實了bean元屬性可以用來代替<qualifier/>子元素。如果可獲得<qualifier/>,它和它的屬性優先順序更高,如果當前沒有限定符,自動裝配機制會將<meta/>內的值作為備用,正如下面的例子中的最後兩個bean定義。

<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="MovieQualifier">
            <attribute key="format" value="VHS"/>
            <attribute key="genre" value="Action"/>
        </qualifier>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="MovieQualifier">
            <attribute key="format" value="VHS"/>
            <attribute key="genre" value="Comedy"/>
        </qualifier>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <meta key="format" value="DVD"/>
        <meta key="genre" value="Action"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <meta key="format" value="BLURAY"/>
        <meta key="genre" value="Comedy"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

</beans>

3.9.5 Using generics as autowiring qualifiers

In addition to the @Qualifier annotation, it is also possible to use Java generic types as an implicit form of qualification. For example, suppose you have the following configuration:

除了@Qualifier註解外,也可以使用Java的泛型型別作為限定符的一種隱式方式。例如,假設你有如下配置:

@Configuration
public class MyConfiguration {

    @Bean
    public StringStore stringStore() {
        return new StringStore();
    }

    @Bean
    public IntegerStore integerStore() {
        return new IntegerStore();
    }

}

Assuming that beans above implement a generic interface, i.e. Store<String> and Store<Integer>, you can @Autowire the Store interface and the generic will be used as a qualifier:

假設上面的beans實現了一個泛型介面,例如,Store<String>Store<Integer>,你可以@Autowire Store介面,泛型將作為限定符使用:

@Autowired
private Store<String> s1; // <String> qualifier, injects the stringStore bean

@Autowired
private Store<Integer> s2; // <Integer> qualifier, injects the integerStore bean

Generic qualifiers also apply when autowiring Lists, Maps and Arrays:

當自動裝配ListsMapsArrays時,也會應用泛型限定符:

// Inject all Store beans as long as they have an <Integer> generic
// Store<String> beans will not appear in this list
@Autowired
private List<Store<Integer>> s;

3.9.6 CustomAutowireConfigurer

The CustomAutowireConfigurer is a BeanFactoryPostProcessor that enables you to register your own custom qualifier annotation types even if they are not annotated with Spring’s @Qualifier annotation.

CustomAutowireConfigurer是一個能使你註冊自己的定製限定符註解型別的BeanFactoryPostProcessor,即使它們不能使用Spring的@Qualifier註解進行註解。

<bean id="customAutowireConfigurer"
        class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
    <property name="customQualifierTypes">
        <set>
            <value>example.CustomQualifier</value>
        </set>
    </property>
</bean>

The AutowireCandidateResolver determines autowire candidates by:

  • the autowire-candidate value of each bean definition

  • any default-autowire-candidates pattern(s) available on the <beans/> element

  • the presence of @Qualifier annotations and any custom annotations registered with the CustomAutowireConfigurer

AutowireCandidateResolver通過下面的方式決定自動裝配的候選目標:

  • 每個bean定義的autowire-candidate

  • <beans/>元素可獲得的任何default-autowire-candidates模式

  • 存在@Qualifier註解和任何在CustomAutowireConfigurer中註冊的定製註解

When multiple beans qualify as autowire candidates, the determination of a “primary” is the following: if exactly one bean definition among the candidates has a primary attribute set to true, it will be selected.

當多個beans符合條件成為自動裝配的候選目標時,”primary” bean的決定如下:如果在候選目標中某個確定的bean中的primary特性被設為true,它將被選為目標bean。

3.9.7 @Resource

Spring also supports injection using the JSR-250 @Resource annotation on fields or bean property setter methods. This is a common pattern in Java EE 5 and 6, for example in JSF 1.2 managed beans or JAX-WS 2.0 endpoints. Spring supports this pattern for Spring-managed objects as well.

Spring也支援使用JSR-250 @Resource對欄位或bean屬性setter方法進行注入。這是在Java EE 5和6中的一種通用模式,例如在JSF 1.2管理的beans或JAX-WS 2.0的端點。Spring對它管理的物件也支援這種模式。

@Resource takes a name attribute, and by default Spring interprets that value as the bean name to be injected. In other words, it follows by-name semantics, as demonstrated in this example:

@Resource採用名字屬性,預設情況下Spring將名字值作為要注入的bean的名字。換句話說,它遵循by-name語義,下面的例子證實了這一點:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource(name="myMovieFinder")
    public void setMovie