Spring Core 之 Annotation-based Container Configuration(基于注解的容器配置)


生词汇总:

  • raise ------------------------------------ 提高, 提出, 养
  • accommodate -------------------------- 容纳, 迁就, 和解
  • in favor of ----------------------------------- 有利于,赞成
  • semantic ----------------------------------- 语义
  • demonstrate ------------------------------- 演示, 表明, 示范
  • preference --------------------------------- 偏爱,优先权
  • associate -------------------------------------- 关联、联合、联想
  • narrowing ------------------------------------------ 缩小
  • constitute --------------------------------------- 构成、组成、组合、占比
  • criteria ------------------------------------------ 准则、标准、规范、尺度
  • resort ------------------------------------------ 采取、玩弄、娱乐场、度假胜地
  • generic ---------------------------------------- 通用的、泛型
  • in addition to ---------------------------------------- 除此之外
  • interpret ---------------------------------------------- 解释、翻译
  • lenient -------------------------------------------- 宽容、宽泛
  • effort ---------------------------------------------- 努力、功夫
  • provided ------------------------------------------ 假定
  • populated ----------------------------------------- 填充

一、Are annotations better than XML for configuring Spring?(注解方式是否比XML方式配置Spring更好)

The introduction of annotation-based configuration 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 is worth pointing out that through its JavaConfig option, Spring lets annotations be used in a non-invasive way, without touching the target components source code and that.

基于注解的配置的引入提出了这种方法是否比 XML“更好”的问题。简短的回答是“视情况而定”.全面一点的回答是每一种方法都有它的优点和缺点,并且通常它取决于开发人员决定哪一种方法更适合他们。由于它们的定义方式,注解提供大量的上下文在他们的声明中,从而使配置更加简短。然而,XML方式的优势在于组件装配不需要触碰他们的源代码或者重编译它们。有些开发者喜欢不触碰源代码的XML,一些开发人员更喜欢在源代码中进行装配,而其他人则认为带注释的类不再是 POJO,而且配置变得分散且更难控制。不管选择哪一种,Spring都能很好的兼容,即使混合使用。值得指出的是,通过其 JavaConfig 选项,Spring 允许以非侵入性方式使用注释,而无需触及目标组件源代码等。

Annotation injection is performed before XML injection. Thus, the XML configuration overrides the annotations for properties wired through both approaches.

注解注入在 XML 注入之前执行。因此,两种方法同时使用时XML 配置会覆盖通过注解配置的属性。

二、@Required

The @Required annotation applies to bean property setter methods,as in the following example:
@Required注解应用于bean的属性设置方法,如下实例所示:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

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

    // ...
}

This annotation 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 NullPointerException instances or the like later on. We still recommend 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类中使用断言assert,对一些必须的引用做强制检测,即使当你在容器外使用这个类。

The @Required annotation and RequiredAnnotationBeanPostProcessor are formally deprecated as of Spring Framework 5.1, in favor of using constructor injection for required settings.

@@Required注解和RequiredAnnotationBeanPostProcessor在Spring5.1及以后已经正式的被标记为过时了。赞成使用构造函数注入进行所需的设置。

三、Using @Autowired

使用@Autowired注解进行注入时,要确保你已经在容器中配置了相应类型的bean实例可以用于注入。

You can apply the @Autowired annotation to constructors, as the following example shows:
你可以将@Autowired注解用于构造器,如下例所示:

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

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

    // ...
}

As of Spring Framework 4.3, an @Autowired annotation on such a constructor is no longer necessary if the target bean defines only one constructor to begin with. However, if several constructors are available and there is no primary/default constructor, at least one of the constructors must be annotated with @Autowired in order to instruct the container which one to use.

从spring4.3开始,如果一个bean中只有一个构造器,那么构造器上使用@Autowired不再是必须的。然而,如果有多个可用的构造器并且没有哪一个被标明为primary或default构造器,至少其中一个构造器上需要使用@Autowired,让容器知道使用哪一个构造器。

You can also apply the @Autowired annotation to traditional setter methods, as the following example shows:

你也可以将 @Autowired 注释应用于传统的 setter 方法,如以下示例所示:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

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

    // ...
}

You can apply @Autowired to fields as well and even mix it with constructors, as the following example shows:

您也可以将 @Autowired 应用于字段,甚至将其与构造函数混合使用,如下例所示:

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    private MovieCatalog movieCatalog;

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

    // ...
}

You can also instruct Spring to provide all beans of a particular type from the ApplicationContext by adding the @Autowired annotation to a field or method that expects an array of that type, as the following example shows:

你也可以通过在数组类型的一个字段或者有数组类型参数的方法上使用@Autowired注解让spring提供该指定类型的所有bean实例,注入到该数组中,如下所示:

public class MovieRecommender {

    @Autowired
    private MovieCatalog[] movieCatalogs;

    // ...
}

public class MovieRecommender {

    private Set<MovieCatalog> movieCatalogs;

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

    // ...
}

Your target beans can implement the org.springframework.core.Ordered interface or use the @Order or standard @Priority annotation if you want items in the array or list to be sorted in a specific order. Otherwise, their order follows the registration order of the corresponding target bean definitions in the container.You can declare the @Order annotation at the target class level and on @Bean methods, potentially for individual bean definitions (in case of multiple definitions that use the same bean class). @Order values may influence priorities at injection points.Note that the standard javax.annotation.Priority annotation is not available at the @Bean level, since it cannot be declared on methods. Its semantics can be modeled through @Order values in combination with @Primary on a single bean for each type.

如果你想在自动注入的数组或者list中有顺序的存储bean实例,你的bean可以实现org.springframework.core.Ordered接口或者使用@Order和@Priority注解。否则,它们的顺序就是注册时的顺序。你可以在类级别和有@Bean注解的方法级别上使用@Order注解。@Order的值可能影响注入时的优先级。要注意的是javax.annotation.Priority注解不能用在@Bean方法级别,也不能用在平普通方法上。它的语义可以通过@Order 值结合@Primary 在每个类型的单个bean 上建模。

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

即使是map类型的实例也可以被装配,只要map的key是String类型的。map的Value可以是任何类型,如下例所示:

public class MovieRecommender {

    private Map<String, MovieCatalog> movieCatalogs;

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

    // ...
}

By default, autowiring fails when no matching candidate beans are available for a given injection point. In the case of a declared array, collection, or map, at least one matching element is expected.The default behavior is to treat annotated methods and fields as indicating required dependencies. You can change this behavior as demonstrated in the following example, enabling the framework to skip a non-satisfiable injection point through marking it as non-required (i.e., by setting the required attribute in @Autowired to false):

默认情况下,如果没有匹配的bean实例可用于装配,自动注入就会失败。对于声明的数组、集合或映射,至少需要一个匹配元素。默认行为是将带注释的方法和字段视为所指示的依赖项为必须。你可以更改此行为,如下例所示,通过将不可满足的注入点标记为非必需(即,通过将 @Autowired 中的 required 属性设置为 false),使框架能够跳过不可满足的注入点:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

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

    // ...
}

As of Spring Framework 5.0, you can also use a @Nullable annotation (of any kind in any package — for example, javax.annotation.Nullable from JSR-305) or just leverage Kotlin builtin null-safety support:

从 Spring Framework 5.0 开始,还可以使用 @Nullable 注释(任何包中的任何类型 — 例如,来自 JSR-305 的 javax.annotation.Nullable)或仅利用 Kotlin 内置的空安全支持:

public class SimpleMovieLister {

    @Autowired
    public void setMovieFinder(@Nullable MovieFinder movieFinder) {
        ...
    }
}

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

@Autowired、@Inject、@Value 和 @Resource 注解由 Spring BeanPostProcessor 实现处理。这意味着你不能在自己的 BeanPostProcessor 或 BeanFactoryPostProcessor 类(如果有)中应用这些注解。这些类必须使用 XML 或 Spring @Bean 方法显式“装配”。

四、Fine-tuning Annotation-based Autowiring with @Primary

使用@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 becomes the autowired value.
Consider the following configuration that defines firstMovieCatalog as the primary MovieCatalog:

由于使用基于类的自动注入可能导致有多个候选者存在,通常需要对选择过程做更多控制。其中一种方法就是使用spring的@Primary注解。当有多个候选bean都可以注入到某个依赖作为值时,使用@Primary注解指定的bean会获得优先权。也就是说如果多个候选者中明确只有一个bean使用了@Primary,那么该bean就会是被注入的值。

参考以下将 firstMovieCatalog 定义为首要MovieCatalog 的配置:

@Configuration
public class MovieConfiguration {

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

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

    // ...
}

With the preceding configuration, the following MovieRecommender is autowired with the firstMovieCatalog:

根据前面的配置,以下MovieRecommender 类中将会选择firstMovieCatalog注入:

public class MovieRecommender {

    @Autowired
    private MovieCatalog movieCatalog;

    // ...
}

四、Fine-tuning Annotation-based Autowiring with Qualifiers(使用Qualifier对基于注解的自动注入进行微调)

使用@Qualifier对基于注解的自动装配进行微调

@Primary is an effective way to use autowiring by type with several instances when one primary candidate can be determined. When you need more control over the selection process, you can use Spring’s @Qualifier annotation. 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, as shown in the following example:

对于使用基于类型的自动注入有多个候选者实例时使用@Primary指定优先的候选者是一种有效的方法。当你需要对选择过程进行更多的控制,你可以使用spring的@Qualifier注解。通过对指定参数管理一个预选值(预选值通常是bean的id或者name),缩小类型匹配者集合,以至于只有指定的那个bean被选择注入。在最简单的案列中,预选值可以是一个文本字符,如下所示:

public class MovieRecommender {

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

    // ...
}

You can also specify the @Qualifier annotation on individual constructor arguments or method parameters, as shown in the following example:

你也可以在单​​个构造函数参数或方法参数上指定 @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;
    }

    // ...
}

Qualifiers also apply to typed collections, as discussed earlier — for example, to Set. 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. Rather, they constitute filtering criteria. For example, you can define multiple MovieCatalog beans with the same qualifier value “action”, all of which are injected into a Set annotated with @Qualifier(“action”).

@Quilifier也可以用于集合类型,就像前面讨论的 Set一样。在该例中,所有匹配quilifier声明的bean将会整体作为一个集合注入。这意味着qualifier对应的不一定需要是唯一的,然而,它们构成了过滤规则。例如,你可以使用相同的限定符值“action”定义多个 MovieCatalog bean,所有这些 bean 都被注入到一个用 @Qualifier(“action”) 注释的 Set 中。

That said, if you intend to express annotation-driven injection by name, do not primarily use @Autowired, even if it is capable of selecting by bean name among type-matching candidates. 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 is considered within those type-selected candidates only (for example, matching an account qualifier against beans marked with the same qualifier label).

也就是说,如果你打算按名称来使用注解驱动的注入,请不要主要使用 @Autowired,即使它能够在类型匹配的候选中按 bean 名称进行选择。取而代之的是,使用 JSR-250 @Resource 注释,该注解在语义上定义为通过其唯一名称标识特定的目标组件,声明的类型与匹配过程无关。@Autowired 有相当但不同的语义:在按类型选择候选 bean 后,指定的 String 限定符值仅在那些类型选择的候选对象中考虑(例如,将帐户限定符与标记有相同限定符标签的 bean 匹配)。

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, you can match collection, Map, and array types 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, you can use qualifier values to select among same-typed collections, as outlined in the previous paragraph.

对于本身定义为集合、映射或数组类型的 bean,@Resource 是一个很好的解决方案,通过唯一名称引用特定的集合或数组 bean。也就是说,从 4.3 开始,你也可以通过 Spring 的 @Autowired 类型匹配算法来匹配集合、映射和数组类型,只要元素类型信息保留在@Bean 返回类型签名或集合继承层次结构中。在这种情况下,您可以使用限定符值在相同类型的集合中进行选择,如上一段所述。

As of 4.3, @Autowired also considers self references for injection (that is, 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, you should use self references as a last resort only (for example, 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, you can use @Resource, which may obtain a proxy back to the current bean by its unique name.

从 4.3 开始,@Autowired 还考虑注入的自引用(即当前注入的 bean 是自己)。注意,自注入是一种回调。对其他组件的常规依赖始终具有优先级。从这个意义上说,自引用不参与常规的候选人选择,因此从不作为首要选择。相反,它们总是以最低的优先级结束。在实践中,你应该仅将自引用作为最后的手段(例如,通过 bean 的事务代理调用同一实例上的其他方法)。在这种情况下,考虑将受影响的方法分解为单独的委托 bean。或者,您可以使用@Resource,它可以通过其唯一名称获取返回当前 bean 的代理。

@Autowired applies to fields, constructors, and multi-argument methods, allowing for narrowing through qualifier annotations at the parameter level. In contrast, @Resource is supported only for fields and bean property setter methods with a single argument. As a consequence, you should stick with qualifiers if your injection target is a constructor or a multi-argument method.
You can create your own custom qualifier annotations. To do so, define an annotation and provide the @Qualifier annotation within your definition, as the following example shows:

@Autowired 用于字段、构造函数和多参数方法,允许通过参数级别的限定符注解来缩小范围。相比之下,@Resource 仅支持字段和带有单个参数的 bean 属性 setter 方法。因此,如果你的注入目标是构造函数或多参数方法,您应该坚持使用限定符。你可以创建自己的自定义限定符注解。为此,请定义注解并在定义中提供 @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, as the following example shows:

然后,你可以在自动装配的字段和参数上提供自定义限定符,如以下示例所示:

public class MovieRecommender {

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

    private MovieCatalog comedyCatalog;

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

    // ...
}

In some cases, using an annotation without a value may suffice. This can 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 can be searched when no Internet connection is available. First, define the simple annotation, as the following example shows:

在某些情况下,使用没有值的注解可能就足够了。当注解用于更通用的目的并且可以应用于多种不同类型的依赖项时,这可能很有用。例如,你可能想提供一个离线目录,当没有可用的 Internet 连接时可以搜索该目录。首先,定义简单的注解,如下例所示:

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

}

Then add the annotation to the field or property to be autowired, as shown in the following example:

然后将注解添加到要自动装配的字段或属性中,如下例所示:

public class MovieRecommender {

    @Autowired
    @Offline 
    private MovieCatalog offlineCatalog;

    // ...
}

Now the bean definition only needs a qualifier type, as shown in the following example:

<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, defined as follows:

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, as the following example shows:
要自动装配的字段使用自定义的限定符进行注解,并包含两个属性的值:genre和format,如以下示例所示:

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 you can use bean meta attributes instead of the <qualifier/> elements. If available, the\ element and its attributes take precedence, but the autowiring mechanism falls back on the values provided within the\ tags if no such qualifier is present, as in the last two bean definitions in the following example:

最后,bean 定义应该包含匹配的限定符值。此示例还演示了你可以使用 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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://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>

五、Using Generics as Autowiring Qualifiers(使用泛型作为注入限定符)

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

除了@Qualifier注解之外,你可以使用泛型作为隐含的限定符。例如,假定你有如下配置:

@Configuration
public class MyConfiguration {

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

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

Assuming that the preceding beans implement a generic interface, (that is, Store and Store), you can @Autowire the Store interface and the generic is used as a qualifier, as the following example shows:

假设上面的bean实现了一个泛型接口(例如Store<String> Store<Integer>),你可以使用@Autowired在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, Map instances and arrays. The following example autowires a generic List:

当注入list、map和数组实例时也可以应用泛型限定符,下例展示了如何注入一个泛型list:

// 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;

六、Using CustomAutowireConfigurer(使用自定义注入配置器)

CustomAutowireConfigurer is a BeanFactoryPostProcessor that lets you register your own custom qualifier annotation types, even if they are not annotated with Spring’s @Qualifier annotation. The following example shows how to use CustomAutowireConfigurer:

CustomAutowireConfigurer 是一个BeanFactoryPostProcessor ,使你可以注册你自定义的限定符注解类,即使它们没有被spring的@Qualifier注解。下面的例子展示了如何使用CustomAutowireConfigurer:

<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:

AutowireCandidateResolver 通过以下规则来决定注入的候选bean:

  • The autowire-candidate value of each bean definition(每个bean中autowire-canidate定义的值)
  • Any default-autowire-candidates patterns available on the <beans/> element(<beans/> 元素上可用的任何 default-autowire-candidates 模式)
  • The presence of @Qualifier annotations and any custom annotations registered with the CustomAutowireConfigurer(存在@Qualifier 注解以及向 CustomAutowireConfigurer 注册的任何自定义注解)

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

当有多个bean满足资格作为候选bean时,将会按照是否有primary决定,如果所有候选bean中明确的有一个primary,它就会被选择。

七、Injection with @Resource

Spring also supports injection by using the JSR-250 @Resource annotation (javax.annotation.Resource) on fields or bean property setter methods. This is a common pattern in Java EE: for example, in JSF-managed beans and JAX-WS endpoints. Spring supports this pattern for Spring-managed objects as well.@Resource takes a name attribute. By default, Spring interprets that value as the bean name to be injected. In other words, it follows by-name semantics, as demonstrated in the following example:

Spring 还通过在字段或 bean 属性 setter 方法上使用 JSR-250 @Resource 注释 (javax.annotation.Resource) 来支持注入。在javaEE中这是一个通用的模式,也就是说任何容器框架都应该支持@Resource进行注入。例如,在 JSF 管理的 bean 和 JAX-WS 端点中。对于 Spring 管理的对象,Spring 也支持这种模式。@Resource 接收一个name 属性。默认情况下,Spring 将该值解释为要注入的 bean 名称。换句话说,它遵循按名称语义,如以下示例所示:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource(name="myMovieFinder") 
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}

If no name is explicitly specified, the default name is derived from the field name or setter method. In case of a field, it takes the field name. In case of a setter method, it takes the bean property name. The following example is going to have the bean named movieFinder injected into its setter method:

如果没有传递name属性的值,默认会取被注解的字段名或者setter方法中属性名作为name属性的值。也就是说,如果是字段,则采用字段名称。在 setter 方法的情况下,它采用参数名称。下面的例子将把名为 movieFinder 的 bean 注入到它的 setter 方法中:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

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

八、Using @Value

@Value is typically used to inject externalized properties:

@Value通常用于注入外部属性:

@Component
public class MovieRecommender {

    private final String catalog;

    public MovieRecommender(@Value("${catalog.name}") String catalog) {
        this.catalog = catalog;
    }
}

With the following configuration:

@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig { }

And the following application.properties file:

catalog.name=MovieCatalog

In that case, the catalog parameter and field will be equal to the MovieCatalog value.

在上面的例子中,catalog参数和字段的值将会是MovieCatalog

A default lenient embedded value resolver is provided by Spring. It will try to resolve the property value and if it cannot be resolved, the property name (for example ${catalog.name}) will be injected as the value. If you want to maintain strict control over nonexistent values, you should declare a PropertySourcesPlaceholderConfigurer bean, as the following example shows:

Spring 默认提供了一个宽松的嵌入值解析器。它将尝试解析属性值,如果无法解析,则属性名称(例如 ${catalog.name})将作为值注入。如果你想对不存在的值保持严格的控制,你应该声明一个PropertySourcesPlaceholderConfigurer bean,如下例所示:

@Configuration
public class AppConfig {

     @Bean
     public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
           return new PropertySourcesPlaceholderConfigurer();
     }
}

When configuring a PropertySourcesPlaceholderConfigurer using JavaConfig, the @Bean method must be static.

使用 JavaConfig 配置 PropertySourcesPlaceholderConfigurer 时,@Bean 方法必须是静态的。

Using the above configuration ensures Spring initialization failure if any ${} placeholder could not be resolved. Spring Boot configures by default a PropertySourcesPlaceholderConfigurer bean that will get properties from application.properties and application.yml files.

如果无法解析任何 ${} 占位符,则使用上述配置可确保 Spring 初始化失败。Spring Boot 默认配置了一个 PropertySourcesPlaceholderConfigurer bean,它将从 application.properties 和 application.yml 文件中获取属性。

Built-in converter support provided by Spring allows simple type conversion (to Integer or int for example) to be automatically handled. Multiple comma-separated values can be automatically converted to String array without extra effort.It is possible to provide a default value as following:

Spring 提供的内置转换器支持允许自动处理简单的类型转换(例如到 Integer 或 int)。多个逗号分隔的值可以自动转换为 String 数组,无需额外的功夫。可以提供如下默认值:(:后为默认值)

@Component
public class MovieRecommender {

    private final String catalog;

    public MovieRecommender(@Value("${catalog.name:defaultCatalog}") String catalog) {
        this.catalog = catalog;
    }
}

A Spring BeanPostProcessor uses a ConversionService behind the scene to handle the process for converting the String value in @Value to the target type. If you want to provide conversion support for your own custom type, you can provide your own ConversionService bean instance as the following example shows:

Spring BeanPostProcessor使用一个ConversionService来处理将@Value中的字符串值替换为目标类型的过程。如果你想为你自己的自定义类型提供转换支持,你可以提供你自己的 ConversionService bean 实例,如下例所示:

@Configuration
public class AppConfig {

    @Bean
    public ConversionService conversionService() {
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
        conversionService.addConverter(new MyCustomConverter());
        return conversionService;
    }
}

When @Value contains a SpEL expression the value will be dynamically computed at runtime as the following example shows:

当 @Value 包含 SpEL 表达式时,该值将在运行时动态计算,如下例所示:

@Component
public class MovieRecommender {

    private final String catalog;

    public MovieRecommender(@Value("#{systemProperties['user.catalog'] + 'Catalog' }") String catalog) {
        this.catalog = catalog;
    }
}

九、Using @PostConstruct and @PreDestroy

The CommonAnnotationBeanPostProcessor not only recognizes the @Resource annotation but also the JSR-250 lifecycle annotations: javax.annotation.PostConstruct and javax.annotation.PreDestroy. Introduced in Spring 2.5, the support for these annotations offers an alternative to the lifecycle callback mechanism described in initialization callbacks and destruction callbacks. Provided that the CommonAnnotationBeanPostProcessor is registered within the Spring ApplicationContext, a method carrying one of these annotations is invoked at the same point in the lifecycle as the corresponding Spring lifecycle interface method or explicitly declared callback method. In the following example, the cache is pre-populated upon initialization and cleared upon destruction:

CommonAnnotationBeanPostProcessor 不仅可以识别 @Resource 注释,还可以识别 JSR-250 生命周期注释:javax.annotation.PostConstruct 和 javax.annotation.PreDestroy。Spring 在 2.5 中将其引入,对这些注解的支持提供了对初始化回调和销毁回调中描述的生命周期回调机制的替代方案。假设 CommonAnnotationBeanPostProcessor 是在 Spring ApplicationContext 中注册的,携带这些注解之一的方法在生命周期中与相应的 Spring 生命周期接口方法或显式声明的回调方法的同一点被调用。在以下示例中,缓存在初始化时预填充并在销毁时清除:

public class CachingMovieLister {

    @PostConstruct
    public void populateMovieCache() {
        // populates the movie cache upon initialization...
    }

    @PreDestroy
    public void clearMovieCache() {
        // clears the movie cache upon destruction...
    }
}

Like @Resource, the @PostConstruct and @PreDestroy annotation types were a part of the standard Java libraries from JDK 6 to 8. However, the entire javax.annotation package got separated from the core Java modules in JDK 9 and eventually removed in JDK 11. If needed, the javax.annotation-api artifact needs to be obtained via Maven Central now, simply to be added to the application’s classpath like any other library.

与@Resource 一样,@PostConstruct 和 @PreDestroy 注释类型是 JDK 6 到 8 的标准 Java 库的一部分。然而,整个 javax.annotation 包在 JDK 9 中与核心 Java 模块分离,最终在 JDK 11 中被删除。如果需要,现在需要通过 Maven Central 获取 javax.annotation-api 工件,只需像任何其他库一样将其添加到应用程序的类路径中即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值