【Spring】Spring Framework Reference Documentation中文版5

7.9 Annotation-based container configuration

基于容器的注解配置

 

Are annotations better than XML for configuring Spring?

对应spring来说,注解配置比xml配置好吗?

 

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.

基于注解的配置介绍来源于这种方式是否比xml要好。简要回答是看情况。复杂点来说,每一种选择都各有利弊,并且通常取决于开发者决定哪个策略更适合。根据他们的定义,注解提供了很多他们定义中的上下文,来实现简单方便的配置。然而,xml文件可以在不修改源代码的情况下惊醒配置。一些开发者倾向于接近源代码,另外一些则认为注解会破坏pojo并且使得配置难以被控制。

 

No matter the choice, Spring can accommodate both styles and even mix them together. Its 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都可以使用甚至可以混合使用。可以通过java配置选项,spring也允许非侵入的方式,不触及目标源代码,所有的配置风格在spring tool suite中都支持。

 

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 Springs dependency injection. Essentially, the @Autowired annotation provides the same capabilities as described in Section 7.4.5, Autowiring collaboratorsbut 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的定义,开发者将配置移入到类中,通过在类、方法、属性上使用注解来配置组件。在章节“例子:RequiredAnnotationBeanPostProcessor”中使用BeanPostProcessor来连接注解是springIOC容器常见的一种扩展方式。例如,spring2.0中介绍了使用@Required注解来声明必须的属性。spirng2.5允许相同的方式来驾驭spring的依赖注入。本质上,@Autowired注解提供了相同的功能在章节7.4.5中描述,“自动注入组件”有更细粒度的控制和更好的适应性。spring2.5也添加了JSR250中的注解,例如@PostConstruct@PreDestroyspring3.0中添加了JSR330中的注解(为java的依赖注入)包括javax.inject包中@Inject@Named。详细内容见7.11

 

[Note]

注意

 

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定义,但是他们也可以如下的定义,在基于xmlspring配置中。(注意需要保护context命名空间):

 

<?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.)

(潜在的注册了post-processors包括AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessorPersistenceAnnotationBeanPostProcessor及上面提及的RequiredAnnotationBeanPostProcessor

 

[Note]

注意

 

<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 22.2, The DispatcherServletfor more information.

<context:annotation-config/>只查找在相同应用上下文定义的bean的注解。这也意味着,如果你在用于DispatcherServletWebApplicationContext上使用了<context:annotation-config/>,他只会检查你控制器中使用的@Autowired,而不是你的服务层。详细内容见22.2章节“DispatcherServlet”。

 

7.9.1 @Required

 

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

@Required注解应用beanset方法中,如下

 

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属性的异常,这样可以避免后续的空指针异常。并且强烈建议你断言类本身在初始化方法中。这样可以强制在引用即便是这个类在容器外部使用。

 

7.9.2 @Autowired

 

[Note]

注意

 

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

JSR330@Inject注解可以用于替代spring@Autowired注解,如下面的例子。详见7.11

 

You can apply the @Autowired annotation to constructors:

你可以在构造器上使用@Autowired注解

 

public class MovieRecommender {

 

    private final CustomerPreferenceDao customerPreferenceDao;

 

    @Autowired

    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {

        this.customerPreferenceDao = customerPreferenceDao;

    }

 

    // ...

 

}

 

[Note]

注意

 

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.

spirng4.3中,@Autowired可以不在修饰构造器如果目标bean只有一个构造器时。如果有多个构造器,则至少有一个需要被修饰来告诉容器使用哪个构造器。

 

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

正如期望的,@Autowired注解也可以用于传统的set方法:

 

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:

也可以从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;

    }

 

    // ...

 

}

 

[Tip]

提示

 

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注解,如果你希望数组或list中的元素可以按照一定的顺序排序。

 

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:

甚至Maps也可以被期望的字符串类型的key值注入。map的值可以是被期望的类型的beankey应该是相对应的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.

默认情况在,自动注入在没有一个匹配时会失败,默认的行为是对修饰的方法、构造器和属性的依赖是必须的。下面的行为可以改变这种描述。

 

public class SimpleMovieLister {

 

    private MovieFinder movieFinder;

 

    @Autowired(required=false)

    public void setMovieFinder(MovieFinder movieFinder) {

        this.movieFinder = movieFinder;

    }

 

    // ...

 

}

 

[Note]

注意

 

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.

每个类中只有一个被注解修饰的构造器可以是必须的,多个非必须的构造器时允许的。在这种情况下,在每个符合条件的构造器中,spring会选择参数最多那个构造器。

 

@Autowireds 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.

建议使用@Autowired注解来替换@Required注解。required属性可以指定属性不是自动注入为目的,如果不被自动注入的话会被忽略。@Required,在另一方面,强制属性以任何容器支持的方法设置。如果没有可以设置的值会抛出一个异常。

 

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.

你也可以使用@Autowired来修饰常用的依赖:BeanFactoryApplicationContextEnvironmentResourceLoaderApplicationEventPublisherMessageSource。这些即可和他们的子接口如ConfigurableApplicationContextResourcePatternResolver都可以被自动注入而不需要特殊的设置。

 

public class MovieRecommender {

 

    @Autowired

    private ApplicationContext context;

 

    public MovieRecommender() {

    }

 

    // ...

 

}

 

[Note]

注意

 

@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注解通过springBeanPostProcessor实现来处理,也就意味着你不能使用这些注解在你自己的BeanPostProcessorBeanFactoryPostProcessor类型中。这些类型必须通过xml或用@Bean来修饰。

 

7.9.3 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 Springs @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.

基于类型的注入可能会出现多种选择,因此建议更加细微的控制选择的过程。一种方式就是使用@Primary注解。@Primary指定一个特殊的bean对于多个候选值应该给出对某个单值的偏爱。如果只有一个primarybean存在,那将会被注入值。

 

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

 

7.9.4 Fine-tuning annotation-based autowiring with qualifiers

使用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, Springs @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注解。你可以使用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的定义如下。qualifier的属性值为mainbean与同名的构造器参数相互连接。

 

<?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的名字作为默认的qualifier值来处理。你可以使用idmain定义一个bean来代替内置的qualifier元素,也可以实现相同的匹配结果。然而,尽管你可以使用这种规范通过name来引用bean@Autowired实际上是使用可选语义限定符实现类型的注入。这就意味着,即使是bean的名字的后备,也缩小了类型匹配的范围,而且不用特意指明beanid。有意义的qualifier的值如mainEMEApersistent,表达一个依赖于beanid的组件的字符串,可以自动生成在上面例子中的那个匿名的bean的定义。

 

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").

qualifier也可以应用于集合,就像上面讨论的那样,例如,Set<MovieCatalog>。在这个例子中,所有匹配的bean都根据定义的qualifier来作为一个集合注入。这意味着qualifier并不一定是唯一的,他们更像是用于过滤的条件。例如,你可以定义多个MovieCatalogbean使用相同的qualifier值为action,所有的这些都会注入@Qualifier("action")修饰的Set<MovieCatalog>

 

[Tip]

提示

 

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.

如果你倾向于表达基于name的注解注入,最好不要首选使用@Autowired注解,尽管他可以配合@Qualifier来实现这样的功能。作为代替,JSR250@Resource注解,就是为了根据唯一的name来定义特定的目标组件的,在匹配时不相关与声明的类型。@Autowired有不同的语义,在通过类型选择相关的bean之后,定义的qualifier的值将被作为考虑来进行匹配,例如,匹配accountqualifier使用相同的qualifier标签被标记。

 

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 Springs @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.

对于定义为collection/map或数组时,@Resource是一个好的选择,指向特定的集合或数字通过唯一的名字来匹配。就像4.3节描述的,collection/map和数组类型可以通过spring@Autowired类型匹配算法一样,只要元素的类型信息在@Bean中定义,返回的类型签名或集合继承关系。在这种情况,qualifier的值可以用于选择相同类型的集合在前面规定的概述中。

 

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 beans 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.

4.3节中,@Autowired也被考虑自引用注入,例如,指向已经被注入的bean。注意自注入是一个后备方案,优先应该注入其他的组件。在这种场景中,自引用一般不作为候选,而且总是处于最低的优先级。在练习中,自注入应该作为最后的选择,例如,在相同的实例上调用相同的方法通过bean的传统代理:在这种情况下考虑从bean中分离中相关的方法。作为代替,使用@Resource可以获得代理来通过唯一的name来指向当前的bean

 

@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可以应用于属性、构造器和多参数的方法,允许缩小范围通过qualifier注解在参数级别。作为区别,@Resource只能在属性或beanset方法上修饰单个参数。作为一个结论,如果你需要通过构造器注入或多参数方法注入时可以考虑qualifier注解。

 

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

你可以创建自定义的qualifier注解。简单的定义一个注解并在定义中使用@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:

然后你使用自定义的qualifier注解来自动注入属性和参数:

 

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的定义信息。在bean元素下使用qualifier子元素定义类型和参数来匹配你自定义的注解。类型匹配注解类名的全限定名。或者,作为规范在不存在name冲突是,你可以使用类名。在下面的例子中描述了这两种方式。

 

<?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 7.10, Classpath scanning and managed components, you will see an annotation-based alternative to providing the qualifier metadata in XML. Specifically, see Section 7.10.8, Providing qualifier metadata with annotations.

7.10节中,“类路径扫描和管理组件”,你会看到基于注解的来提供xml中的qualifier元数据。见7.10.8节,“使用注解提供qualifier元数据”。

 

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:

在一些例子中,可以运行使用注解而不指定value。注解可以服务于通用的目标会更加有用,而且可以跨不同类型的依赖。例如,你可以提供线下的catalog并且可以在没有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:

然后用注解修饰fieldproperty用于自动注入:

 

public class MovieRecommender {

 

    @Autowired

    @Offline

    private MovieCatalog offlineCatalog;

 

    // ...

 

}

 

Now the bean definition only needs a qualifier type:

现在bean的定义中只需要声明qualifier的类型就可以:

 

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

你也可以自定义qualifier注解来接受名字属性来代替简单的value属性。如果多个属性被定义在field或参数上,则一个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.

需要被自动注入的自定义qualifier必须包含两个属性: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的定义应该包含匹配的qualifier的参数值。这个例子也描述了bean的元数据属性应该使用qualifier子元素来替代。如果可以,qualifier和他的属性应该优先,但是自动注入策略考虑meta标签中提供的值,如果没有这样的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="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>

 

7.9.5 Using generics as autowiring qualifiers

使用泛型作为自动注入qualifier

 

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泛型作为qualification的一种实现形式。例如,假设你有这样的配置:

 

@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>,你可以用@Autowired来修饰Store接口,泛型将会被使用当做一个qualifier

 

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

泛型的qualifier也支持自动注入ListMaps和数组

 

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

 

7.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 Springs @Qualifier annotation.

CustomAutowireConfigurer是一个BeanFactoryPostProcessor,允许你注册你自定义的qualifier注解类型,尽管他们没有使用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:

AutowireCandidateResolver处理自动注入的条件

 

    the autowire-candidate value of each bean definition

每个bean定义中自动注入的值

    any default-autowire-candidates pattern(s) 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 the following: if exactly one bean definition among the candidates has a primary attribute set to true, it will be selected.

当多个bean可以匹配,使用如下方式来决定:这些候选的bean中有一个主要属性被设置为true

 

7.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也支持使用JSR250@Resource注解修饰fieldset方法来实现注入。这对于JavaEE56来说是很常见的,例如,在JSF1.2管理beanJAX-WS2.0spring也支持这种形式对于spring管理的object

 

@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注解有一个name属性,默认使用bean的名字来实现注入。换句话说,就像下面的例子一样,按照名字匹配实现注入。

 

public class SimpleMovieLister {

 

    private MovieFinder movieFinder;

 

    @Resource(name="myMovieFinder")

    public void setMovieFinder(MovieFinder movieFinder) {

        this.movieFinder = movieFinder;

    }

 

}

 

If no name is specified explicitly, 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. So the following example is going to have the bean with name "movieFinder" injected into its setter method:

如果没有明确指定name属性,默认的name从修饰的fieldset方法中来判断。如果是field,就使用fieldname,如果是方法,就使用beanproperty的那么。因此下面的例子中会使用“moveFinder”为名的bean进行注入:

 

public class SimpleMovieLister {

 

    private MovieFinder movieFinder;

 

    @Resource

    public void setMovieFinder(MovieFinder movieFinder) {

        this.movieFinder = movieFinder;

    }

 

}

 

[Note]

注意

 

The name provided with the annotation is resolved as a bean name by the ApplicationContext of which the CommonAnnotationBeanPostProcessor is aware. The names can be resolved through JNDI if you configure Springs SimpleJndiBeanFactory explicitly. However, it is recommended that you rely on the default behavior and simply use Springs JNDI lookup capabilities to preserve the level of indirection.

提供了name的注解将通过beanname来处理,通过受CommonAnnotationBeanPostProcessor控制的pplicationContext。如果你配置的springSimpleJndiBeanFactory话也可以使用JNDI来处理name。然而,建议你使用默认行为和简单使用springJNDI查找能力来包含间接的级别。

 

In the exclusive case of @Resource usage with no explicit name specified, and similar to @Autowired, @Resource finds a primary type match instead of a specific named bean and resolves well-known resolvable dependencies: the BeanFactory, ApplicationContext, ResourceLoader, ApplicationEventPublisher, and MessageSource interfaces.

如果不使用name属性的@Resource注解的用法和@Autowired的用法相似,@Resource查找主要的类型匹配代替特定namebean并解决常见的依赖:BeanFactoryApplicationContextResourceLoaderApplicationEventPublisherMessageSource接口。

 

Thus in the following example, the customerPreferenceDao field first looks for a bean named customerPreferenceDao, then falls back to a primary type match for the type CustomerPreferenceDao. The "context" field is injected based on the known resolvable dependency type ApplicationContext.

在下面的例子中,customerPreferenceDao属性首先需找namecustomerPreferenceDaobean,失败之后寻找主要的类型匹配CustomerPreferenceDaobeancontext将会注入已知类型的ApplicationContext

 

public class MovieRecommender {

 

    @Resource

    private CustomerPreferenceDao customerPreferenceDao;

 

    @Resource

    private ApplicationContext context;

 

    public MovieRecommender() {

    }

 

    // ...

 

}

 

7.9.8 @PostConstruct and @PreDestroy

 

The CommonAnnotationBeanPostProcessor not only recognizes the @Resource annotation but also the JSR-250 lifecycle annotations. Introduced in Spring 2.5, the support for these annotations offers yet another alternative to those 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 example below, the cache will be pre-populated upon initialization and cleared upon destruction.

CommonAnnotationBeanPostProcessor并不只会处理@Resource注解,也会处理JSR250中生命周期注解。在spring2.5中,支持这些注解并且会在初始化和销毁时进行回调。如果CommonAnnotationBeanPostProcessorspringApplicationContext中注册了,那么在相应的时间点对应的方法会被调用。在下面的例子中,cache将会在开始时创建,然后在销毁时被清除。

 

public class CachingMovieLister {

 

    @PostConstruct

    public void populateMovieCache() {

        // populates the movie cache upon initialization...

    }

 

    @PreDestroy

    public void clearMovieCache() {

        // clears the movie cache upon destruction...

    }

 

}

 

[Note]

 

For details about the effects of combining various lifecycle mechanisms, see the section called Combining lifecycle mechanisms.

更多的有关影响可变的生命周期的说明,见章节“组合生命周期策略”。

 

7.10 Classpath scanning and managed components

类路径扫描和管理组件

 

Most examples in this chapter use XML to specify the configuration metadata that produces each BeanDefinition within the Spring container. The previous section (Section 7.9, Annotation-based container configuration) demonstrates how to provide a lot of the configuration metadata through source-level annotations. Even in those examples, however, the "base" bean definitions are explicitly defined in the XML file, while the annotations only drive the dependency injection. This section describes an option for implicitly detecting the candidate components by scanning the classpath. Candidate components are classes that match against a filter criteria and have a corresponding bean definition registered with the container. This removes the need to use XML to perform bean registration; instead you can use annotations (for example @Component), AspectJ type expressions, or your own custom filter criteria to select which classes will have bean definitions registered with the container.

大部分的例子使用xml来定义配置元数据使得spring的容器可以处理。前面的章节(章节7.9“基于注解的容器配置”)描述了如何通过使用一系列在源代码级别使用注解来描述。即便是在这些例子中,基本的bean定义也是明确的用xml来定义,注解智能驾驭依赖注入。在这节将介绍通过扫描类路径来实现对备选组件的探测。候选组件就是类,这些类满足一定的条件,并且和容器中定义的bean的依赖有关。这样就避免了使用xml来配置bean的定义,作为代替,你可以使用注解来定义(例如@Component),AspectJ类型表达式或你自定义的匹配规则来选择容器中bean的依赖。

 

[Note]

注意

 

Starting with Spring 3.0, many features provided by the Spring JavaConfig project are part of the core Spring Framework. This allows you to define beans using Java rather than using the traditional XML files. Take a look at the @Configuration, @Bean, @Import, and @DependsOn annotations for examples of how to use these new features.

spring3.0开始,许多spring JavaConfig项目提供的组件成为了spring框架核心的一部分。这允许你铜鼓java来定义bean而不是使用传统的xml文件。可以看一下@Configuration@Bean@Import@DependsOn注解来了解如何使用这些新特性。

 

7.10.1 @Component and further stereotype annotations

@Component和更多模板注解

 

The @Repository annotation is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO). Among the uses of this marker is the automatic translation of exceptions as described in Section 20.2.2, Exception translation.

@Repository注解用于描述存储的角色(常见的就是DAO)。使用这个注解是自动异常translation,见20.2.2节“异常translation

 

Spring provides further stereotype annotations: @Component, @Service, and @Controller. @Component is a generic stereotype for any Spring-managed component. @Repository, @Service, and @Controller are specializations of @Component for more specific use cases, for example, in the persistence, service, and presentation layers, respectively. Therefore, you can annotate your component classes with @Component, but by annotating them with @Repository, @Service, or @Controller instead, your classes are more properly suited for processing by tools or associating with aspects. For example, these stereotype annotations make ideal targets for pointcuts. It is also possible that @Repository, @Service, and @Controller may carry additional semantics in future releases of the Spring Framework. Thus, if you are choosing between using @Component or @Service for your service layer, @Service is clearly the better choice. Similarly, as stated above, @Repository is already supported as a marker for automatic exception translation in your persistence layer.

spinrg提供了很多模板注解:@Component@Service@Controller@Component是用于spring管理组件的泛型模板。@Repository@Service@Controller@Component的特例用于更清晰的定义,例如,在持久化、服务和表现层。你可以将你的组件类都声明为@Component,但是通过@Repository@Service@Controller会更加的方便出来并与切面相互结合。例如,这些策略可以成为目标的切入点。而且这些在spirng框架的后续版本中会有特殊的功能。如果你在服务层纠结使用@Component还是@Service,那很明显@Service是更好的选择。同样,在开始的时候,@Repository支持持久层的异常translation

 

7.10.2 Meta-annotations

元注解

 

Many of the annotations provided by Spring can be used as meta-annotations in your own code. A meta-annotation is simply an annotation that can be applied to another annotation. For example, the @Service annotation mentioned above is meta-annotated with @Component:

所有spring提供的注解都可以作为你代码中的元注解。一个元注解可以很简单的运用在另一个注解上。例如,@Service注解就在元注解@Component上。

 

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Component // Spring will see this and treat @Service in the same way as @Component

//spirng会看到这个声明,并且处理的方式和@Component一样

public @interface Service {

 

    // ....

}

 

Meta-annotations can also be combined to create composed annotations. For example, the @RestController annotation from Spring MVC is composed of @Controller and @ResponseBody.

元注解也可以合并用于创建组合注解。例如,spring mvc中的@RestController注解就是@Controller@ResponseBody的组合。

 

In addition, composed annotations may optionally redeclare attributes from meta-annotations to allow user customization. This can be particularly useful when you want to only expose a subset of the meta-annotations attributes. For example, Springs @SessionScope annotation hardcodes the scope name to session but still allows customization of the proxyMode.

额外的,组合注解可以减少元注解属性的定义允许自定义。如果你希望使用元注解的部分属性时这个功能很有用。例如,spring@SessionScope注解硬编码了session的范围名但是仍然允许自定义proxyMode

 

@Target({ElementType.TYPE, ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Scope(WebApplicationContext.SCOPE_SESSION)

public @interface SessionScope {

 

    /**

     * Alias for {@link Scope#proxyMode}.

     * <p>Defaults to {@link ScopedProxyMode#TARGET_CLASS}.

     */

    @AliasFor(annotation = Scope.class)

    ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

 

}

 

@SessionScope can then be used without declaring the proxyMode as follows:

@SessionScope可以用下面的方式定义proxyMode

 

@Service

@SessionScope

public class SessionScopedService {

    // ...

}

 

Or with an overridden value for the proxyMode as follows:

或者覆盖proxyMode的值如下

 

@Service

@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)

public class SessionScopedUserService implements UserService {

    // ...

}

 

For further details, consult the Spring Annotation Programming Model.

详见spring注解编程模型

 

7.10.3 Automatically detecting classes and registering bean definitions

自动探测类和注册bean定义

 

Spring can automatically detect stereotyped classes and register corresponding BeanDefinitions with the ApplicationContext. For example, the following two classes are eligible for such autodetection:

spring可以自动探测模板类并且使用ApplicationContext来注册相应的bean定义。例如,下面的两个类就是可以被探测到的。

 

@Service

public class SimpleMovieLister {

 

    private MovieFinder movieFinder;

 

    @Autowired

    public SimpleMovieLister(MovieFinder movieFinder) {

        this.movieFinder = movieFinder;

    }

 

}

 

@Repository

public class JpaMovieFinder implements MovieFinder {

    // implementation elided for clarity

}

 

To autodetect these classes and register the corresponding beans, you need to add @ComponentScan to your @Configuration class, where the basePackages attribute is a common parent package for the two classes. (Alternatively, you can specify a comma/semicolon/space-separated list that includes the parent package of each class.)

需要被自动探测的类需要注册相应的bean,你需要在@Configuration类上添加@ComponentScan注解,然后基本包路径就是为两个类的通用父包。(相应的,你可以使用逗号、分行和空格来分割父包的列表)

 

@Configuration

@ComponentScan(basePackages = "org.example")

public class AppConfig  {

    ...

}

 

[Note]

注意

 

for concision, the above may have used the value attribute of the annotation, i.e. ComponentScan("org.example")

为了方便,上面的定义也可以用注解的属性来定义,如ComponentScan("org.example")

 

The following is an alternative using XML

或者使用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: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:component-scan base-package="org.example"/>

 

</beans>

 

[Tip]

提示

 

The use of <context:component-scan> implicitly enables the functionality of <context:annotation-config>. There is usually no need to include the <context:annotation-config> element when using <context:component-scan>.

使用<context:component-scan>暗示着允许<context:annotation-config>的功能。所以当使用<context:component-scan>时可以忽略<context:annotation-config>

 

[Note]

注意

 

The scanning of classpath packages requires the presence of corresponding directory entries in the classpath. When you build JARs with Ant, make sure that you do not activate the files-only switch of the JAR task. Also, classpath directories may not get exposed based on security policies in some environments, e.g. standalone apps on JDK 1.7.0_45 and higher (which requires 'Trusted-Library' setup in your manifests; see http://stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources).

用于扫描的包路径必须要以相对路径来表示。当你使用Ant打包JAR时,保证你不需要激活JAR task的只文件功能。类路径在一些环境的安全路径中不会暴露,例如基于1.7.0_45或以上版本的单独app(需要在你的清单文件设置“信赖库”,见http://stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources

 

Furthermore, the AutowiredAnnotationBeanPostProcessor and CommonAnnotationBeanPostProcessor are both included implicitly when you use the component-scan element. That means that the two components are autodetected and wired together - all without any bean configuration metadata provided in XML.

更进一步的,AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor都隐含的包含了当你使用组件扫描元素时。这就意味着这两个组件已经被扫描注入了,不需要在xml中提供bean的配置。

 

[Note]

注意

 

You can disable the registration of AutowiredAnnotationBeanPostProcessor and CommonAnnotationBeanPostProcessor by including the annotation-config attribute with a value of false.

你可以关闭AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor的自动注册通过使用annotation-config属性,并指定属性值为false

 

7.10.4 Using filters to customize scanning

在自定义扫描中使用过滤器

 

By default, classes annotated with @Component, @Repository, @Service, @Controller, or a custom annotation that itself is annotated with @Component are the only detected candidate components. However, you can modify and extend this behavior simply by applying custom filters. Add them as includeFilters or excludeFilters parameters of the @ComponentScan annotation (or as include-filter or exclude-filter sub-elements of the component-scan element). Each filter element requires the type and expression attributes. The following table describes the filtering options.

默认的,声明@Component@Repository@Service@Controller或自定义注解修饰的类都会被探测为组件。然而,你可以修改和扩展这种行为通过应用自定义的过滤器。可以在@Component注解中说明包括的过滤器和排除的过滤器(或使用component-scan的子元素include-filterexclude-filter)。每个过滤器元素需要类型或表达式类型。下面的表描述的可选的过滤器选项。

 

Table 7.5. Filter Types

过滤器类型

Filter Type

过滤类型

Example Expression

表达式例子

Description

描述

annotation (default)

默认

org.example.SomeAnnotation

An annotation to be present at the type level in target components.

一个注解用于表达目标组件的类型级别

assignable

org.example.SomeClass

A class (or interface) that the target components are assignable to (extend/implement).

可指定目标组件的类或接口

aspectj

org.example..*Service+

An AspectJ type expression to be matched by the target components.

一个AspectJ类型表达式用于匹配目标组件

regex

org\.example\.Default.*

A regex expression to be matched by the target components class names.

通过类名的正则表达式来匹配目标组件

custom

org.example.MyTypeFilter

A custom implementation of the org.springframework.core.type .TypeFilter interface.

org.springframework.core.type .TypeFilter接口的自定义实现

The following example shows the configuration ignoring all @Repository annotations and using "stub" repositories instead.

下面的例子展示了所有的@Repository注解但是忽略使用Stubrepository

 

@Configuration

@ComponentScan(basePackages = "org.example",

        includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),

        excludeFilters = @Filter(Repository.class))

public class AppConfig {

    ...

}

 

and the equivalent using XML

含义和使用xml一样

 

<beans>

    <context:component-scan base-package="org.example">

        <context:include-filter type="regex"

                expression=".*Stub.*Repository"/>

        <context:exclude-filter type="annotation"

                expression="org.springframework.stereotype.Repository"/>

    </context:component-scan>

</beans>

 

[Note]

注意

 

You can also disable the default filters by setting useDefaultFilters=false on the annotation or providing use-default-filters="false" as an attribute of the <component-scan/> element. This will in effect disable automatic detection of classes annotated with @Component, @Repository, @Service, @Controller, or @Configuration.

你可以在注解上设置useDefaultFilters=false来关闭默认的过滤器或在component-scan元素上使用use-default-filters="false"作为元素属性。这将会关闭对使用@Component@Repository@Service@Controller@Configuration注解的自动扫描。

 

7.10.5 Defining bean metadata within components

在组件中定义bean的元数据

 

Spring components can also contribute bean definition metadata to the container. You do this with the same @Bean annotation used to define bean metadata within @Configuration annotated classes. Here is a simple example:

spring组件允许为容器定义bean定义的元数据。你可以使用@Bean定义bean的元数据在@Configuration修饰的类中。下面是个简单的例子:

 

@Component

public class FactoryMethodComponent {

 

    @Bean

    @Qualifier("public")

    public TestBean publicInstance() {

        return new TestBean("publicInstance");

    }

 

    public void doWork() {

        // Component method implementation omitted

    }

 

}

 

This class is a Spring component that has application-specific code contained in its doWork() method. However, it also contributes a bean definition that has a factory method referring to the method publicInstance(). The @Bean annotation identifies the factory method and other bean definition properties, such as a qualifier value through the @Qualifier annotation. Other method level annotations that can be specified are @Scope, @Lazy, and custom qualifier annotations.

这个类是spring的组件,在他的doWork方法中包含应用特定的代码。然而他也定义了bean的定义使用的工厂方法指向publicInstance方法。@Bean定义了工厂方法和其他bean的定义属性,例如@Qualifier注解的值。其他方法级别的注解可以定义的如@Scope@Lazy和自定义qualifier注解。

 

[Tip]

提示

 

In addition to its role for component initialization, the @Lazy annotation may also be placed on injection points marked with @Autowired or @Inject. In this context, it leads to the injection of a lazy-resolution proxy.

除了组件初始化的角色外,@Lazy注解也可以额替代@Autowired@Inject来实现注入点。在上下文中,他是延迟代理的注入。

 

Autowired fields and methods are supported as previously discussed, with additional support for autowiring of @Bean methods:

自动注入的属性和方法的支持在之前讨论过,其他的是由自动注入的@Bean方法支持的:

 

@Component

public class FactoryMethodComponent {

 

    private static int i;

 

    @Bean

    @Qualifier("public")

    public TestBean publicInstance() {

        return new TestBean("publicInstance");

    }

 

    // use of a custom qualifier and autowiring of method parameters

// 使用自定义的qualifier和自动注入方法的参数

    @Bean

    protected TestBean protectedInstance(

            @Qualifier("public") TestBean spouse,

            @Value("#{privateInstance.age}") String country) {

        TestBean tb = new TestBean("protectedInstance", 1);

        tb.setSpouse(spouse);

        tb.setCountry(country);

        return tb;

    }

 

    @Bean

    private TestBean privateInstance() {

        return new TestBean("privateInstance", i++);

    }

 

    @Bean

    @RequestScope

    public TestBean requestScopedInstance() {

        return new TestBean("requestScopedInstance", 3);

    }

 

}

 

The example autowires the String method parameter country to the value of the Age property on another bean named privateInstance. A Spring Expression Language element defines the value of the property through the notation #{ <expression> }. For @Value annotations, an expression resolver is preconfigured to look for bean names when resolving expression text.

例子中给字符串类型的方法参数country自动注入了另一个名为privateInstancebeanage属性。属性值通过spring的表达式定义,类似#{}的样子。对于@Value的注解,表达式首先解析bean的名字。

 

As of Spring Framework 4.3, you may also declare a factory method parameter of type InjectionPoint (or its more specific subclass DependencyDescriptor) in order to access the requesting injection point that triggers the creation of the current bean. Note that this will only apply to the actual creation of bean instances, not to the injection of existing instances. As a consequence, this feature makes most sense for beans of prototype scope. For other scopes, the factory method will only ever see the injection point which triggered the creation of a new bean instance in the given scope: for example, the dependency that triggered the creation of a lazy singleton bean. Use the provided injection point metadata with semantic care in such scenarios.

spring框架4.3中,你可以定义一个使用InjectionPoint类型参数的工厂方法(或他的子类DependencyDescriptor)以便于在当前bean创建的时候访问请求注入。注意只能用于创建bean的实例,而不能用语注入已有的实例。因此,这个特性大部分用于原型的bean。对于其他的范围,工厂方法只能看见注入点,这个注入点触发了给定范围新bean的创建:例如,延迟加载单例bean创建触发的依赖。在这种场景中使用提供的注入点元数据。

 

@Component

public class FactoryMethodComponent {

 

    @Bean @Scope("prototype")

    public TestBean prototypeInstance(InjectionPoint injectionPoint) {

        return new TestBean("prototypeInstance for " + injectionPoint.getMember());

    }

}

 

The @Bean methods in a regular Spring component are processed differently than their counterparts inside a Spring @Configuration class. The difference is that @Component classes are not enhanced with CGLIB to intercept the invocation of methods and fields. CGLIB proxying is the means by which invoking methods or fields within @Bean methods in @Configuration classes creates bean metadata references to collaborating objects; such methods are not invoked with normal Java semantics but rather go through the container in order to provide the usual lifecycle management and proxying of Spring beans even when referring to other beans via programmatic calls to @Bean methods. In contrast, invoking a method or field in an @Bean method within a plain @Component class has standard Java semantics, with no special CGLIB processing or other constraints applying.

正常spring组件中的@Bean方法和用@Configuration修饰的spring类处理方式不同。区别在于@Component修饰的类不会使用CGLIB来加强以实现对方法和属性的调用。cglib代理意味着在@Configuration的类中调用方法和属性,创建的bean元数据指向组合object。这样的方法不再被java声明调用,而是通过容器用于提供通常的生命周期管理和springbean的代理通过调用@Bean方法执行其他的bean。相对的,使用普通的@Component类可以调用@Bean方法,而不再使用特殊的cglbi处理或其他假设的应用。

 

[Note]

注意

 

You may declare @Bean methods as static, allowing for them to be called without creating their containing configuration class as an instance. This makes particular sense when defining post-processor beans, e.g. of type BeanFactoryPostProcessor or BeanPostProcessor, since such beans will get initialized early in the container lifecycle and should avoid triggering other parts of the configuration at that point.

你可以定义静态的@Bean方法,允许他们在不创建实例的前提下被调用。这使得定义后处理bean时出现了特例,例如,BeanFactoryPostProcessor类型或BeanPostProcessor类型,将会在容器生命周期中提前初始化避免和配置点的其他部分相关联。

 

Note that calls to static @Bean methods will never get intercepted by the container, not even within @Configuration classes (see above). This is due to technical limitations: CGLIB subclassing can only override non-static methods. As a consequence, a direct call to another @Bean method will have standard Java semantics, resulting in an independent instance being returned straight from the factory method itself.

注意,调用@Bean修饰的静态方法是不会被容器拦截的,即使是使用了@Configuration注解的类。这是由于技术的限制:cglib的子类只能覆盖非静态方法。因此,直接调用另一个@Bean的方法将会有标准的java语义,在一个独立的实例中将会从工厂方法中直接返回。

 

The Java language visibility of @Bean methods does not have an immediate impact on the resulting bean definition in Springs container. You may freely declare your factory methods as you see fit in non-@Configuration classes and also for static methods anywhere. However, regular @Bean methods in @Configuration classes need to be overridable, i.e. they must not be declared as private or final.

@Bean方法的可见性不会直接影响到spring容器中bean的定义。你可以在没有@Configuration修饰的类中直接定义工厂方法或静态方法。然而,在@Configuration类中的@Bean方法需要被覆盖,因此,你不能使用privatefinal来修饰方法。

 

@Bean methods will also be discovered on base classes of a given component or configuration class, as well as on Java 8 default methods declared in interfaces implemented by the component or configuration class. This allows for a lot of flexibility in composing complex configuration arrangements, with even multiple inheritance being possible through Java 8 default methods as of Spring 4.2.

@Bean方法将会在给定组件或配置类中被定义,也可以在Java8中的默认方法定义在接口实现中通过组件或配置类。这样在复杂的配置安排中会很便利,即使是多重集成也将可能通过java8的默认方法在spirng4.2中。

 

Finally, note that a single class may hold multiple @Bean methods for the same bean, as an arrangement of multiple factory methods to use depending on available dependencies at runtime. This is the same algorithm as for choosing the "greediest" constructor or factory method in other configuration scenarios: The variant with the largest number of satisfiable dependencies will be picked at construction time, analogous to how the container selects between multiple @Autowired constructors.

最后,一个单独的类可以有多个@Bean方法在相同的bean中,多个工厂方法可以用于在运行时实现依赖。选择最好的构造器或工厂方法的策略是一样的在其他配置的场景中。最适合的依赖将被选用在构造期间,和容器选择多个@Autowired构造器的策略是一样的。

 

7.10.6 Naming autodetected components

自动探测组件的命名

 

When a component is autodetected as part of the scanning process, its bean name is generated by the BeanNameGenerator strategy known to that scanner. By default, any Spring stereotype annotation (@Component, @Repository, @Service, and @Controller) that contains a name value will thereby provide that name to the corresponding bean definition.

当一个组件作为扫描进程的一部分作为探测,他的bean的名字将会通过BeanNameGenerator生成然后被扫描器所知。默认的,任何的spring策略注解(@Component@Repository@Service@Controller)都包含一个name值可以定义相关的bean定义。

 

If such an annotation contains no name value or for any other detected component (such as those discovered by custom filters), the default bean name generator returns the uncapitalized non-qualified class name. For example, if the following two components were detected, the names would be myMovieLister and movieFinderImpl:

如果这样的注解不包含name的值(例如通过自定义过滤器发现的),默认的bean的名字生成将返回首字母小写的类全限定名。例如,如果下面的两个组件被探测到,那名字将会是myMoveListermoveFinderImple

 

@Service("myMovieLister")

public class SimpleMovieLister {

    // ...

}

 

@Repository

public class MovieFinderImpl implements MovieFinder {

    // ...

}

 

[Note]

注意

 

If you do not want to rely on the default bean-naming strategy, you can provide a custom bean-naming strategy. First, implement the BeanNameGenerator interface, and be sure to include a default no-arg constructor. Then, provide the fully-qualified class name when configuring the scanner:

如果你不希望默认的命名策略,你可以提供自定义的命名策略。首先,实现BeanNameGenerator接口,然后保证包含一个默认无参构造器。然而,在配置扫描器时提供全限定的类名。

 

@Configuration

@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)

public class AppConfig {

    ...

}

 

<beans>

    <context:component-scan base-package="org.example"

        name-generator="org.example.MyNameGenerator" />

</beans>

 

As a general rule, consider specifying the name with the annotation whenever other components may be making explicit references to it. On the other hand, the auto-generated names are adequate whenever the container is responsible for wiring.

作为通用的规则,考虑使用注解定义那么淡其他组件或许定义明显的引用。另一方面,自动生成的名字是可以胜任需求的,当容器配置bean时。

 

7.10.7 Providing a scope for autodetected components

对自动探测的组件提供范围

 

As with Spring-managed components in general, the default and most common scope for autodetected components is singleton. However, sometimes you need a different scope which can be specified via the @Scope annotation. Simply provide the name of the scope within the annotation:

作为spring管理的通用的组件,大部分被探测的组件是单例的。然而,有时你需要不同的范围则需要使用@Scope注解。简单的使用这个注解提供范围的名字。

 

@Scope("prototype")

@Repository

public class MovieFinderImpl implements MovieFinder {

    // ...

}

 

For details on web-specific scopes, see Section 7.5.4, Request, session, global session, application, and WebSocket scopes.

关于web特殊的范围,见7.5.4节“Requestsessionglobal sessionapplicationWebSocket范围”

 

[Note]

注意

 

To provide a custom strategy for scope resolution rather than relying on the annotation-based approach, implement the ScopeMetadataResolver interface, and be sure to include a default no-arg constructor. Then, provide the fully-qualified class name when configuring the scanner:

对于组件处理提供自定义的范围处理,实现ScopeMetadataResolver接口,并且抱着有一个无参的构造方法。然后在配置扫描器的时候提供全限定的类名:

 

@Configuration

@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)

public class AppConfig {

    ...

}

 

<beans>

    <context:component-scan base-package="org.example"

            scope-resolver="org.example.MyScopeResolver" />

</beans>

 

When using certain non-singleton scopes, it may be necessary to generate proxies for the scoped objects. The reasoning is described in the section called Scoped beans as dependencies. For this purpose, a scoped-proxy attribute is available on the component-scan element. The three possible values are: no, interfaces, and targetClass. For example, the following configuration will result in standard JDK dynamic proxies:

当使用一个非单例的范围,需要为这个范围的object生成代理。这个理由描述在章节“范围bean作为依赖”。因为这个原因,一个被代理的属性在组件扫描元素中可见。这三个可取值为nointerfacetargetClass。例如,下面的配置将实现标准的JDK动态代理:

 

@Configuration

@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)

public class AppConfig {

    ...

}

 

<beans>

    <context:component-scan base-package="org.example"

        scoped-proxy="interfaces" />

</beans>

 

7.10.8 Providing qualifier metadata with annotations

通过注解提供全限定元数据

 

The @Qualifier annotation is discussed in Section 7.9.4, Fine-tuning annotation-based autowiring with qualifiers. The examples in that section demonstrate the use of the @Qualifier annotation and custom qualifier annotations to provide fine-grained control when you resolve autowire candidates. Because those examples were based on XML bean definitions, the qualifier metadata was provided on the candidate bean definitions using the qualifier or meta sub-elements of the bean element in the XML. When relying upon classpath scanning for autodetection of components, you provide the qualifier metadata with type-level annotations on the candidate class. The following three examples demonstrate this technique:

7.9.4中讨论的@Qualifier注解,“使用qualifier微调基于注解的自动注入”。那节中的例子描述了@Qualifier注解的使用和自定义qualifier注解来实现微调控制当你处理自动注入时。因为这些例子是基于xmlbean定义,qualifier元数据通过bean定义来提供,使用在xml中的qualifier元素或元子元素。当扫描类路径用于自动探测组件,你在备选类中提供了qualifier元数据在类型级别。下面的三个例子讨论了这种技术:

 

@Component

@Qualifier("Action")

public class ActionMovieCatalog implements MovieCatalog {

    // ...

}

 

@Component

@Genre("Action")

public class ActionMovieCatalog implements MovieCatalog {

    // ...

}

 

@Component

@Offline

public class CachingMovieCatalog implements MovieCatalog {

    // ...

}

 

[Note]

注意

 

As with most annotation-based alternatives, keep in mind that the annotation metadata is bound to the class definition itself, while the use of XML allows for multiple beans of the same type to provide variations in their qualifier metadata, because that metadata is provided per-instance rather than per-class.

作为基于注解的替代,记住注解元数据是和类定义本身相互关联的,使用xml允许多个相同类型的bean提供不同在他们的元数据中,因为元数据提供单个实例而不是单个类。

 

7.11 Using JSR 330 Standard Annotations

使用JSR330标准注解

 

Starting with Spring 3.0, Spring offers support for JSR-330 standard annotations (Dependency Injection). Those annotations are scanned in the same way as the Spring annotations. You just need to have the relevant jars in your classpath.

spring3.0开始,spring提供了对JSR330标准注解的支持(依赖注入)。这些注解将会以相同的方式被spring扫描。你只需要在你的类中有相关的类就可以。

 

[Note]

注意

 

If you are using Maven, the javax.inject artifact is available in the standard Maven repository ( http://repo1.maven.org/maven2/javax/inject/javax.inject/1/). You can add the following dependency to your file pom.xml:

如果你使用Maven,那么以javax.inject作为artifact在标准的Mavan仓库中是可用的(http://repo1.maven.org/maven2/javax/inject/javax.inject/1/)。你可以将下面的依赖加入你的pom.xml文件中。

 

<dependency>

    <groupId>javax.inject</groupId>

    <artifactId>javax.inject</artifactId>

    <version>1</version>

</dependency>

 

7.11.1 Dependency Injection with @Inject and @Named

使用@Inject@Named实现依赖注入

 

Instead of @Autowired, @javax.inject.Inject may be used as follows:

代替了@Autowired@javax.injiect.Inject可以像如下的方式一样使用:

 

import javax.inject.Inject;

 

public class SimpleMovieLister {

 

    private MovieFinder movieFinder;

 

    @Inject

    public void setMovieFinder(MovieFinder movieFinder) {

        this.movieFinder = movieFinder;

    }

 

    public void listMovies() {

        this.movieFinder.findMovies(...);

        ...

    }

}

 

As with @Autowired, it is possible to use @Inject at the field level, method level and constructor-argument level. Furthermore, you may declare your injection point as a Provider, allowing for on-demand access to beans of shorter scopes or lazy access to other beans through a Provider.get() call. As a variant of the example above:

@Autowired注解一样,@Inject也可以修饰field级别、方法级别和构造器参数级别。更进一步,你可以定义你自己的注入点作为Provider,允许依赖访问小范围或延迟访问其他bean通过Provider.get()方法。作为上面例子的变化:

 

import javax.inject.Inject;

import javax.inject.Provider;

 

public class SimpleMovieLister {

 

    private Provider<MovieFinder> movieFinder;

 

    public void listMovies() {

        this.movieFinder.get().findMovies(...);

        ...

    }

}

 

If you would like to use a qualified name for the dependency that should be injected, you should use the @Named annotation as follows:

如果你倾向于使用依赖的全限定名,你可以像下面这个例子一样使用@Named注解:

 

import javax.inject.Inject;

import javax.inject.Named;

 

public class SimpleMovieLister {

 

    private MovieFinder movieFinder;

 

    @Inject

    public void setMovieFinder(@Named("main") MovieFinder movieFinder) {

        this.movieFinder = movieFinder;

    }

 

    // ...

}

 

7.11.2 @Named and @ManagedBean: standard equivalents to the @Component annotation

@Named@ManageBean:标准和@Component注解相同

 

Instead of @Component, @javax.inject.Named or javax.annotation.ManagedBean may be used as follows:

代替@Component@javax.inject.Namedjavax.annotation.ManageBean可以像如下这样使用:

 

import javax.inject.Inject;

import javax.inject.Named;

 

@Named("movieListener") // @ManagedBean("movieListener") could be used as well

public class SimpleMovieLister {

 

    private MovieFinder movieFinder;

 

    @Inject

    public void setMovieFinder(MovieFinder movieFinder) {

        this.movieFinder = movieFinder;

    }

 

    // ...

}

 

It is very common to use @Component without specifying a name for the component. @Named can be used in a similar fashion:

通常使用@Component而不指定名在组件中。@Named也可以这样使用:

 

import javax.inject.Inject;

import javax.inject.Named;

 

@Named

public class SimpleMovieLister {

 

    private MovieFinder movieFinder;

 

    @Inject

    public void setMovieFinder(MovieFinder movieFinder) {

        this.movieFinder = movieFinder;

    }

 

    // ...

}

 

When using @Named or @ManagedBean, it is possible to use component scanning in the exact same way as when using Spring annotations:

当使用@Named@ManageBean,最好和使用spring注解一样使用组件扫描。

 

@Configuration

@ComponentScan(basePackages = "org.example")

public class AppConfig  {

    ...

}

 

[Note]

注意

 

In contrast to @Component, the JSR-330 @Named and the JSR-250 ManagedBean annotations are not composable. Please use Springs stereotype model for building custom component annotations.

@Component对于,JSR330@NamedJSR250@ManageBean是不能组合使用的。请使用spring的策略模型用于构建自定义组件注解。

 

7.11.3 Limitations of JSR-330 standard annotations

使用JSR330标准注解的限制

 

When working with standard annotations, it is important to know that some significant features are not available as shown in the table below:

当使用标准注解时,需要连接一些特性是不支持的,见下表

 

Table 7.6. Spring component model elements vs. JSR-330 variants

spring的组件模型元素 vs JSR330变量

Spring

javax.inject.*

javax.inject restrictions / comments

限制/说明

@Autowired

@Inject

@Inject has no 'required' attribute; can be used with Java 8s Optional instead.

@Inject没有required属性;可以使用Java8Optional替代

@Component

@Named / @ManagedBean

JSR-330 does not provide a composable model, just a way to identify named components.

JSR330没有提供组合模型,只能定义命名组件

@Scope("singleton")

@Singleton

The JSR-330 default scope is like Springs prototype. However, in order to keep it consistent with Springs general defaults, a JSR-330 bean declared in the Spring container is a singleton by default. In order to use a scope other than singleton, you should use Springs @Scope annotation. javax.inject also provides a @Scope annotation. Nevertheless, this one is only intended to be used for creating your own annotations.

JSR330默认范围类似spring的原型。然而,为了和spring保持一致,JSR330定义的beanspriing的容器中默认是单例的。为了使用其他的范围,你需要使用spring@Scope主机。javax.inject也提供了@Scope注解。但只是为了用于构建你自己的注解。

@Qualifier

@Qualifier / @Named

javax.inject.Qualifier is just a meta-annotation for building custom qualifiers. Concrete String qualifiers (like Springs @Qualifier with a value) can be associated through javax.inject.Named.

javax.inject.Qualifier是一个元主机用于构建自定义的qualifier。字符串为值的qualifiers(类似于spring@Qualifier有属性值)可以和javax.inject.Named相互联系。

@Value

-

no equivalent

@Required

-

no equivalent

@Lazy

-

no equivalent

ObjectFactory

Provider

javax.inject.Provider is a direct alternative to Springs ObjectFactory, just with a shorter get() method name. It can also be used in combination with Springs @Autowired or with non-annotated constructors and setter methods.

javax.inject.Provider是springObjectFactory的代替,只是使用get方面。也可以和spring@Autowired一起使用在没有声明构造器和set方法中。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值