2.9 Annotation-based Container Configuration 基于注解的容器配置
Are annotations better than XML for configuring 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, in terms of tooling, all configuration styles are supported by the Spring Tools for Eclipse.
基于注释的配置的引入提出了一个问题,即这种方法是否比XML“更好”。简而言之,答案是“视情况而定”。长篇大论的回答是,每种方法都有其优点和缺点,通常由开发人员决定哪种策略更适合他们。由于它们的定义方式,注释在其声明中提供了大量上下文,从而使配置更短、更简洁。然而,XML擅长在不接触源代码或不重新编译它们的情况下连接组件。一些开发人员喜欢将连接放在接近源的地方,而另一些人则认为带注释的类不再是pojo,而且配置变得分散,更难控制。
无论选择什么,Spring都可以同时容纳两种风格,甚至将它们混合在一起。值得指出的是,通过它的JavaConfig选项,Spring允许以一种非侵入性的方式使用注释,而不涉及目标组件源代码,并且,在工具方面,所有的配置风格都得到了Eclipse的Spring工具的支持。
An alternative to XML setup is provided by annotation-based configuration, which relies 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 Example: The RequiredAnnotationBeanPostProcessor
, using a BeanPostProcessor
in conjunction with annotations is a common means of extending the Spring IoC container. For example, Spring 2.0 introduced the possibility of enforcing required properties with the @Required
annotation. Spring 2.5 made it possible to follow that same general approach to drive Spring’s dependency injection. Essentially, the @Autowired
annotation provides the same capabilities as described in Autowiring Collaborators but with more fine-grained control and wider applicability. Spring 2.5 also added support for JSR-250 annotations, such as @PostConstruct
and @PreDestroy
. Spring 3.0 added support for JSR-330 (Dependency Injection for Java) annotations contained in the javax.inject
package such as @Inject
and @Named
. Details about those annotations can be found in the relevant section.
XML设置的另一种替代方法是基于注释的配置,它依赖于将组件连接起来的字节码元数据,而不是尖括号声明。开发人员不使用XML来描述bean连接,而是通过使用相关类、方法或字段声明上的注释将配置移动到组件类本身。如示例中所述:RequiredAnnotationBeanPostProcessor,将BeanPostProcessor与注释结合使用是扩展Spring IoC容器的一种常见方法。例如,Spring 2.0引入了使用@Required注释强制执行所需属性的可能性。Spring 2.5使得采用相同的通用方法来驱动Spring的依赖项注入成为可能。本质上,@Autowired注解提供了与Autowiring合作者描述的相同的功能,但是更细粒度的控制和更广泛的适用性。Spring 2.5还增加了对JSR-250注释的支持,比如@PostConstruct和@PreDestroy。Spring 3.0增加了对javax中包含的JSR-330 (Java依赖注入)注释的支持。注入包,如@Inject和@Named。有关这些注释的详细信息可以在相关部分找到。
Annotation injection is performed before XML injection. Thus, the XML configuration overrides the annotations for properties wired through both approaches.
注释注入在XML注入之前执行。因此,XML配置覆盖了通过这两种方法连接的属性的配置。
As always, you can register them as individual bean definitions, but they can also be implicitly registered by including the following tag in an XML-based Spring configuration (notice the inclusion of the context
namespace):
与往常一样,您可以将它们注册为单独的bean定义,但是也可以通过在基于xml的Spring配置中包含以下标记来隐式注册它们(请注意上下文名称空间的包含):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
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/>
</beans>
(The implicitly registered post-processors include AutowiredAnnotationBeanPostProcessor
, CommonAnnotationBeanPostProcessor
, PersistenceAnnotationBeanPostProcessor
, and the aforementioned RequiredAnnotationBeanPostProcessor
.)
(隐式注册的后处理器包括AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor和前面提到的RequiredAnnotationBeanPostProcessor。)
-
<context:annotation-config/>
only looks for annotations on beans in the same application context in which it is defined. This means that, if you put<context:annotation-config/>
in aWebApplicationContext
for aDispatcherServlet
, it only checks for@Autowired
beans in your controllers, and not your services. See The DispatcherServlet for more information. -
context:annotation-config/只在定义它的应用程序上下文中查找bean上的注释。这意味着,如果你把context:annotation-config/放在一个DispatcherServlet的WebApplicationContext中,它只会检查你的控制器中的@Autowired bean,而不会检查你的服务。有关更多信息,请参见DispatcherServlet。
2.9.1. @Required
The @Required
annotation applies to bean property setter methods, as in the following example:
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属性,容器将抛出异常。这允许立即执行和显式失败,避免了以后出现NullPointerException实例或类似的情况。我们仍然建议将断言放入bean类本身(例如,放入init方法)。即使在容器外部使用类,这样做也会加强那些必需的引用和值。
-
The
@Required
annotation is formally deprecated as of Spring Framework 5.1, in favor of using constructor injection for required settings (or a custom implementation ofInitializingBean.afterPropertiesSet()
along with bean property setter methods). -
从Spring Framework 5.1开始,@Required注释被正式弃用,支持为所需的设置使用构造函数注入(或InitializingBean.afterPropertiesSet()的自定义实现以及bean属性设置器方法)。
2.9.2 Using @Autowired
-
JSR 330’s
@Inject
annotation can be used in place of Spring’s@Autowired
annotation in the examples included in this section. See here for more details. -
在本节包含的示例中,JSR 330的@Inject注释可以代替Spring的@Autowired注释。详情请看这里。
You can apply the @Autowired
annotation to constructors, as the following example shows:
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, at least one must be annotated with@Autowired
in order to instruct the container which one to use. - 从Spring Framework 4.3开始,如果目标bean只定义一个构造函数,那么就不再需要在这样的构造函数上使用@Autowired注解。但是,如果有多个构造函数可用,那么必须至少有一个用@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 also apply the annotation to methods with arbitrary names and multiple arguments, as the following example shows:
您还可以将该注释应用于具有任意名称和多个参数的方法,如下面的示例所示:
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, 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;
}
// ...
}
Make sure that your target components (for example, MovieCatalog
or CustomerPreferenceDao
) are consistently declared by the type that you use for your @Autowired
-annotated injection points. Otherwise, injection may fail due to a “no type match found” error at runtime.For XML-defined beans or component classes found via classpath scanning, the container usually knows the concrete type up front. However, for @Bean
factory methods, you need to make sure that the declared return type is sufficiently expressive. For components that implement several interfaces or for components potentially referred to by their implementation type, consider declaring the most specific return type on your factory method (at least as specific as required by the injection points referring to your bean).
确保您的目标组件(例如MovieCatalog或CustomerPreferenceDao)是由用于@ autowire注释的注入点的类型一致声明的。否则,注入可能会由于运行时错误“没有找到类型匹配”而失败。
对于通过类路径扫描找到的xml定义的bean或组件类,容器通常预先知道具体的类型。但是,对于@Bean工厂方法,您需要确保声明的返回类型具有足够的表达能力。对于实现多个接口的组件或可能由其实现类型引用的组件,请考虑在工厂方法上声明最特定的返回类型(至少与引用bean的注入点所需的返回类型一样具体)。
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:
您还可以指示Spring通过向需要该类型数组的字段或方法添加@Autowired注释来从ApplicationContext中提供特定类型的所有bean,如下例所示:
public class MovieRecommender {
@Autowired
private MovieCatalog[] movieCatalogs;
// ...
}
The same applies for typed collections, as the following example shows:
类型化集合也是如此,如下例所示:
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, but be aware that they do not influence singleton startup order, which is an orthogonal concern determined by dependency relationships and @DependsOn
declarations.
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.
您的目标bean可以实现org.springframe .core。如果希望数组或列表中的项按特定顺序排序,可以使用@Order或标准的@Priority注释。否则,它们的顺序将遵循容器中相应的目标bean定义的注册顺序。
您可以在目标类级别和@Bean方法上声明@Order注释,可能是针对单个bean定义(如果多个定义使用相同的bean类)。@Order值可能会影响注入点的优先级,但是要注意它们不会影响单例启动顺序,这是一个由依赖关系和@DependsOn声明决定的正交关系。
注意,标准的javax.annotation。在@Bean级别上不能使用Priority注释,因为它不能在方法上声明。它的语义可以通过@Order值与针对每种类型的单个bean上的@Primary组合来建模。
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实例,只要期望的键类型是String,也可以自动生成。映射值包含预期类型的所有bean,键包含相应的bean名称,如下例所示:
public class MovieRecommender