1.12. Java-based Container Configuration
基于 Java 的容器配置
This section covers how to use annotations in your Java code to configure the Spring container. It includes the following topics:
本节介绍如何在 Java 代码中使用注解来配置 Spring 容器。它包括以下主题:
-
Instantiating the Spring Container by Using AnnotationConfigApplicationContext
1.12.1. Basic Concepts: @Bean
and @Configuration
基本概念:@Bean
和@Configuration
The central artifacts in Spring’s new Java-configuration support are @Configuration
-annotated classes and @Bean
-annotated methods.
Spring 新的 Java 配置支持中的核心工件是带 @Configuration
注释的类和带@Bean
注释的方法。
The @Bean
annotation is used to indicate that a method instantiates, configures, and initializes a new object to be managed by the Spring IoC container. For those familiar with Spring’s <beans/>
XML configuration, the @Bean
annotation plays the same role as the <bean/>
element. You can use @Bean
-annotated methods with any Spring @Component
. However, they are most often used with @Configuration
beans.
@Bean
注解用于表示一个方法实例化、配置和初始化一个由 Spring IoC 容器管理的新对象。对于熟悉 Spring 的<beans/>
XML 配置的人来说,注解与元素@Bean
的作用相同。<bean/>
您可以将@Bean
-annotated 方法与任何 Spring 一起 使用@Component
。但是,它们最常与@Configuration
豆类一起使用。
Annotating a class with @Configuration
indicates that its primary purpose is as a source of bean definitions. Furthermore, @Configuration
classes let inter-bean dependencies be defined by calling other @Bean
methods in the same class. The simplest possible @Configuration
class reads as follows:
用 注释一个类@Configuration
表明它的主要目的是作为 bean 定义的来源。此外,@Configuration
类允许通过调用@Bean
同一类中的其他方法来定义 bean 间的依赖关系。最简单的@Configuration
类如下所示:
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
The preceding AppConfig
class is equivalent to the following Spring <beans/>
XML:
前面的AppConfig
类等价于下面的 Spring <beans/>
XML:
<beans>
<bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>
Full @Configuration vs “lite” @Bean mode?
完整的@Configuration 与“精简”@Bean 模式?
When @Bean
methods are declared within classes that are not annotated with @Configuration
, they are referred to as being processed in a “lite” mode. Bean methods declared in a @Component
or even in a plain old class are considered to be “lite”, with a different primary purpose of the containing class and a @Bean
method being a sort of bonus there. For example, service components may expose management views to the container through an additional @Bean
method on each applicable component class. In such scenarios, @Bean
methods are a general-purpose factory method mechanism.
当@Bean
方法在没有用 注释的类中声明时 @Configuration
,它们被称为以“精简”模式处理。在一个或什至在一个普通的旧类中声明的 Bean 方法@Component
被认为是“精简版”,包含类的不同主要目的和一种@Bean
方法在那里是一种奖励。例如,服务组件可以通过@Bean
每个适用组件类上的附加方法向容器公开管理视图。在这种情况下,@Bean
方法是一种通用的工厂方法机制。
Unlike full @Configuration
, lite @Bean
methods cannot declare inter-bean dependencies. Instead, they operate on their containing component’s internal state and, optionally, on arguments that they may declare. Such a @Bean
method should therefore not invoke other @Bean
methods. Each such method is literally only a factory method for a particular bean reference, without any special runtime semantics. The positive side-effect here is that no CGLIB subclassing has to be applied at runtime, so there are no limitations in terms of class design (that is, the containing class may be final
and so forth).
与 full 不同@Configuration
,lite@Bean
方法不能声明 bean 间的依赖关系。相反,它们对其包含组件的内部状态进行操作,并且可以选择对它们可能声明的参数进行操作。因此,这种@Bean
方法不应调用其他 @Bean
方法。每个这样的方法实际上只是特定 bean 引用的工厂方法,没有任何特殊的运行时语义。这里的积极副作用是在运行时不必应用 CGLIB 子类化,因此在类设计方面没有限制(即包含类可能是final
等等)。
In common scenarios, @Bean
methods are to be declared within @Configuration
classes, ensuring that “full” mode is always used and that cross-method references therefore get redirected to the container’s lifecycle management. This prevents the same @Bean
method from accidentally being invoked through a regular Java call, which helps to reduce subtle bugs that can be hard to track down when operating in “lite” mode.
在常见情况下,@Bean
方法将在@Configuration
类中声明,确保始终使用“完整”模式,并且跨方法引用因此被重定向到容器的生命周期管理。这可以防止 @Bean
通过常规 Java 调用意外调用相同的方法,这有助于减少在“精简”模式下操作时难以追踪的细微错误。
The @Bean
and @Configuration
annotations are discussed in depth in the following sections. First, however, we cover the various ways of creating a spring container by using Java-based configuration.
以下部分将深入讨论@Bean
和注释。@Configuration
然而,首先,我们介绍了使用基于 Java 的配置创建 Spring 容器的各种方法。
1.12.2. Instantiating the Spring Container by Using AnnotationConfigApplicationContext
通过使用实例化 Spring 容器AnnotationConfigApplicationContext
The following sections document Spring’s AnnotationConfigApplicationContext
, introduced in Spring 3.0. This versatile ApplicationContext
implementation is capable of accepting not only @Configuration
classes as input but also plain @Component
classes and classes annotated with JSR-330 metadata.
以下部分记录AnnotationConfigApplicationContext
了 Spring 3.0 中引入的 Spring。这种通用ApplicationContext
的实现不仅能够接受 @Configuration
类作为输入,还能够接受普通@Component
类和使用 JSR-330 元数据注释的类。
When @Configuration
classes are provided as input, the @Configuration
class itself is registered as a bean definition and all declared @Bean
methods within the class are also registered as bean definitions.
当@Configuration
类作为输入提供时,@Configuration
类本身被注册为 bean 定义,并且@Bean
类中所有声明的方法也被注册为 bean 定义。
When @Component
and JSR-330 classes are provided, they are registered as bean definitions, and it is assumed that DI metadata such as @Autowired
or @Inject
are used within those classes where necessary.
当提供@Component和JSR-330类时,它们被注册为bean定义,并且假设必要时在这些类中使用DI元数据,例如@Autowired或@Inject。
Simple Construction
简单的构造
In much the same way that Spring XML files are used as input when instantiating a ClassPathXmlApplicationContext
, you can use @Configuration
classes as input when instantiating an AnnotationConfigApplicationContext
. This allows for completely XML-free usage of the Spring container, as the following example shows:
与实例化“ClassPathXmlApplicationContext”时使用Spring XML文件作为输入的方式大致相同,在实例化“AnnotationConfigApplicationContext”时,可以使用“@Configuration”类作为输入。这允许完全不使用XML的Spring容器,如以下示例所示:
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
As mentioned earlier, AnnotationConfigApplicationContext
is not limited to working only with @Configuration
classes. Any @Component
or JSR-330 annotated class may be supplied as input to the constructor, as the following example shows:
如前所述,AnnotationConfigApplicationContext
不仅限于使用@Configuration
类。任何@Component
或 JSR-330 注释类都可以作为输入提供给构造函数,如以下示例所示:
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
The preceding example assumes that MyServiceImpl
, Dependency1
, and Dependency2
use Spring dependency injection annotations such as @Autowired
.
前面的示例假定MyServiceImpl
、Dependency1
和Dependency2
使用 Spring 依赖注入注解,例如@Autowired
.
Building the Container Programmatically by Using register(Class<?>…)
通过使用以编程方式构建容器register(Class<?>…)
You can instantiate an AnnotationConfigApplicationContext
by using a no-arg constructor and then configure it by using the register()
method. This approach is particularly useful when programmatically building an AnnotationConfigApplicationContext
. The following example shows how to do so:
AnnotationConfigApplicationContext
您可以使用无参数构造函数实例化一个,然后使用该register()
方法对其进行配置。这种方法在以编程方式构建AnnotationConfigApplicationContext
. 以下示例显示了如何执行此操作:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class, OtherConfig.class);
ctx.register(AdditionalConfig.class);
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
Enabling Component Scanning with scan(String…)
启用组件扫描scan(String…)
To enable component scanning, you can annotate your @Configuration
class as follows:
要启用组件扫描,您可以@Configuration
如下注释您的类:
@Configuration
@ComponentScan(basePackages = "com.acme")
public class AppConfig {
// ...
}
This annotation enables component scanning. | |
---|---|
此注释启用组件扫描。 |
Experienced Spring users may be familiar with the XML declaration equivalent from Spring’s context: namespace, shown in the following example:<beans> <context:component-scan base-package="com.acme"/> </beans> | |
---|---|
有经验的 Spring 用户可能熟悉 Springcontext: 命名空间中等效的 XML 声明,如下例所示: |
In the preceding example, the com.acme
package is scanned to look for any @Component
-annotated classes, and those classes are registered as Spring bean definitions within the container. AnnotationConfigApplicationContext
exposes the scan(String…)
method to allow for the same component-scanning functionality, as the following example shows:
在前面的示例中,com.acme
扫描包以查找任何 带@Component
注释的类,并且这些类在容器中注册为 Spring bean 定义。AnnotationConfigApplicationContext
公开该 scan(String…)
方法以允许相同的组件扫描功能,如以下示例所示:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("com.acme");
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
}
Remember that @Configuration classes are meta-annotated with @Component , so they are candidates for component-scanning. In the preceding example, assuming that AppConfig is declared within the com.acme package (or any package underneath), it is picked up during the call to scan() . Upon refresh() , all its @Bean methods are processed and registered as bean definitions within the container. | |
---|---|
请记住,@Configuration 类是用元注释 的@Component ,因此它们是组件扫描的候选对象。在前面的示例中,假设AppConfig 在com.acme 包(或下面的任何包)中声明了 ,在调用scan() . 在 之后refresh() ,它的所有@Bean 方法都被处理并注册为容器中的 bean 定义。 |
Support for Web Applications with AnnotationConfigWebApplicationContext
支持 Web 应用程序AnnotationConfigWebApplicationContext
A WebApplicationContext
variant of AnnotationConfigApplicationContext
is available with AnnotationConfigWebApplicationContext
. You can use this implementation when configuring the Spring ContextLoaderListener
servlet listener, Spring MVC DispatcherServlet
, and so forth. The following web.xml
snippet configures a typical Spring MVC web application (note the use of the contextClass
context-param and init-param):
WebApplicationContext
变体AnnotationConfigApplicationContext
可用于AnnotationConfigWebApplicationContext
. 您可以在配置 Spring ContextLoaderListener
servlet 侦听器、Spring MVC DispatcherServlet
等时使用此实现。以下web.xml
代码片段配置了一个典型的 Spring MVC Web 应用程序(注意使用contextClass
context-param 和 init-param):
<web-app>
<!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<!-- Configuration locations must consist of one or more comma- or space-delimited
fully-qualified @Configuration classes. Fully-qualified packages may also be
specified for component-scanning -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.AppConfig</param-value>
</context-param>
<!-- Bootstrap the root application context as usual using ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Declare a Spring MVC DispatcherServlet as usual -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<!-- Again, config locations must consist of one or more comma- or space-delimited
and fully-qualified @Configuration classes -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.web.MvcConfig</param-value>
</init-param>
</servlet>
<!-- map all requests for /app/* to the dispatcher servlet -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
For programmatic use cases, a GenericWebApplicationContext can be used as an alternative to AnnotationConfigWebApplicationContext . See the GenericWebApplicationContext javadoc for details. | |
---|---|
对于编程用例, aGenericWebApplicationContext 可以用作AnnotationConfigWebApplicationContext . 有关详细信息,请参阅 GenericWebApplicationContext javadoc。 |
1.12.3. Using the @Bean
Annotation
使用@Bean
注解
@Bean
is a method-level annotation and a direct analog of the XML <bean/>
element. The annotation supports some of the attributes offered by <bean/>
, such as:
@Bean
是方法级别的注释,是 XML<bean/>
元素的直接模拟。注解支持 提供的一些属性<bean/>
,例如:
-
初始化方法
-
销毁方法
-
自动装配
-
name
.
You can use the @Bean
annotation in a @Configuration
-annotated or in a @Component
-annotated class.
您可以在@Configuration注释或@Component注释类中使用@Bean注释。
Declaring a Bean
声明一个 Bean
To declare a bean, you can annotate a method with the @Bean
annotation. You use this method to register a bean definition within an ApplicationContext
of the type specified as the method’s return value. By default, the bean name is the same as the method name. The following example shows a @Bean
method declaration:
要声明一个 bean,你可以用注解来注解一个方法@Bean
。ApplicationContext
您可以使用此方法在指定为方法返回值的类型中注册 bean 定义。默认情况下,bean 名称与方法名称相同。以下示例显示了一个@Bean
方法声明:
@Configuration
public class AppConfig {
@Bean
public TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
The preceding configuration is exactly equivalent to the following Spring XML:
前面的配置完全等价于下面的 Spring XML:
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
Both declarations make a bean named transferService
available in the ApplicationContext
, bound to an object instance of type TransferServiceImpl
, as the following text image shows:
这两个声明都使 beantransferService
中的可用 beanApplicationContext
绑定到 type 的对象实例TransferServiceImpl
,如以下文本图像所示:
transferService -> com.acme.TransferServiceImpl
You can also use default methods to define beans. This allows composition of bean configurations by implementing interfaces with bean definitions on default methods.
您还可以使用默认方法来定义 bean。这允许通过在默认方法上实现带有 bean 定义的接口来组合 bean 配置。
public interface BaseConfig {
@Bean
default TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
@Configuration
public class AppConfig implements BaseConfig {
}
You can also declare your @Bean
method with an interface (or base class) return type, as the following example shows:
您还可以@Bean
使用接口(或基类)返回类型声明您的方法,如以下示例所示:
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
However, this limits the visibility for advance type prediction to the specified interface type (TransferService
). Then, with the full type (TransferServiceImpl
) known to the container only once the affected singleton bean has been instantiated. Non-lazy singleton beans get instantiated according to their declaration order, so you may see different type matching results depending on when another component tries to match by a non-declared type (such as @Autowired TransferServiceImpl
, which resolves only once the transferService
bean has been instantiated).
但是,这会将高级类型预测的可见性限制为指定的接口类型 ( TransferService
)。TransferServiceImpl
然后,只有在实例化受影响的单例 bean 后,容器才知道完整类型 ( )。非惰性单例 bean 会根据它们的声明顺序进行实例化,因此您可能会看到不同的类型匹配结果,具体取决于另一个组件何时尝试通过未声明的类型进行匹配(例如@Autowired TransferServiceImpl
,仅在transferService
bean 被实例化后才解析)。
If you consistently refer to your types by a declared service interface, your @Bean return types may safely join that design decision. However, for components that implement several interfaces or for components potentially referred to by their implementation type, it is safer to declare the most specific return type possible (at least as specific as required by the injection points that refer to your bean). | |
---|---|
如果您始终通过声明的服务接口引用您的类型,则您的 @Bean 返回类型可以安全地加入该设计决策。但是,对于实现多个接口的组件或可能由其实现类型引用的组件,声明最具体的返回类型可能更安全(至少与引用您的 bean 的注入点所要求的一样具体)。 |
Bean Dependencies
Bean 依赖项
A @Bean
-annotated method can have an arbitrary number of parameters that describe the dependencies required to build that bean. For instance, if our TransferService
requires an AccountRepository
, we can materialize that dependency with a method parameter, as the following example shows:
@Bean-annotated 方法可以具有@Bean
任意数量的参数,这些参数描述了构建该 bean 所需的依赖项。例如,如果我们TransferService
需要一个AccountRepository
,我们可以使用方法参数实现该依赖项,如下例所示:
@Configuration
public class AppConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
The resolution mechanism is pretty much identical to constructor-based dependency injection. See the relevant section for more details.
解析机制与基于构造函数的依赖注入几乎相同。有关详细信息,请参阅相关部分。
Receiving Lifecycle Callbacks
接收生命周期回调
Any classes defined with the @Bean
annotation support the regular lifecycle callbacks and can use the @PostConstruct
and @PreDestroy
annotations from JSR-250. See JSR-250 annotations for further details.
使用注释定义的任何类都@Bean
支持常规生命周期回调,并且可以使用 JSR-250 中的@PostConstruct
和@PreDestroy
注释。有关详细信息,请参阅 JSR-250 注释。
The regular Spring lifecycle callbacks are fully supported as well. If a bean implements InitializingBean
, DisposableBean
, or Lifecycle
, their respective methods are called by the container.
也完全支持常规的 Spring生命周期回调。如果 bean 实现InitializingBean
、DisposableBean
或Lifecycle
,则容器调用它们各自的方法。
The standard set of *Aware
interfaces (such as BeanFactoryAware, BeanNameAware, MessageSourceAware, ApplicationContextAware, and so on) are also fully supported.
还完全支持标准的*Aware
接口集(例如BeanFactoryAware、 BeanNameAware、 MessageSourceAware、 ApplicationContextAware等)。
The @Bean
annotation supports specifying arbitrary initialization and destruction callback methods, much like Spring XML’s init-method
and destroy-method
attributes on the bean
element, as the following example shows:
@Bean
注解支持指定任意初始化和销毁回调方法,很像 Spring XMLinit-method
和元素上的destroy-method
属性bean
,如以下示例所示:
public class BeanOne {
public void init() {
// initialization logic
}
}
public class BeanTwo {
public void cleanup() {
// destruction logic
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public BeanOne beanOne() {
return new BeanOne();
}
@Bean(destroyMethod = "cleanup")
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
By default, beans defined with Java configuration that have a public close or shutdown method are automatically enlisted with a destruction callback. If you have a public close or shutdown method and you do not wish for it to be called when the container shuts down, you can add @Bean(destroyMethod="") to your bean definition to disable the default (inferred) mode.You may want to do that by default for a resource that you acquire with JNDI, as its lifecycle is managed outside the application. In particular, make sure to always do it for a DataSource , as it is known to be problematic on Java EE application servers.The following example shows how to prevent an automatic destruction callback for a DataSource :JavaKotlin@Bean(destroyMethod="") public DataSource dataSource() throws NamingException { return (DataSource) jndiTemplate.lookup("MyDS"); } Also, with @Bean methods, you typically use programmatic JNDI lookups, either by using Spring’s JndiTemplate or JndiLocatorDelegate helpers or straight JNDI InitialContext usage but not the JndiObjectFactoryBean variant (which would force you to declare the return type as the FactoryBean type instead of the actual target type, making it harder to use for cross-reference calls in other @Bean methods that intend to refer to the provided resource here). | |
---|---|
默认情况下,使用 Java 配置定义的具有公共close 或shutdown 方法的 bean 会自动加入销毁回调。如果您有一个公共 close 或shutdown 方法并且您不希望在容器关闭时调用它,您可以添加@Bean(destroyMethod="") 到您的 bean 定义以禁用默认(inferred) 模式。默认情况下,您可能希望对使用 JNDI 获取的资源执行此操作,因为它的生命周期在应用程序之外进行管理。特别是,请确保始终为DataSource .以下示例显示了如何防止 a 的自动销毁回调 DataSource :此外,对于@Bean 方法,您通常使用程序化 JNDI 查找,通过使用 SpringJndiTemplate 或JndiLocatorDelegate 帮助程序或直接 InitialContext 使用 JNDI 但不使用JndiObjectFactoryBean 变体(这将迫使您将返回类型声明为FactoryBean 类型而不是实际的目标类型,从而更难用于其他@Bean 方法中的交叉引用调用,这些方法旨在引用此处提供的资源)。 |
In the case of BeanOne
from the example above the preceding note, it would be equally valid to call the init()
method directly during construction, as the following example shows:
在上述BeanOne
示例的情况下,在构造期间直接调用该init()
方法同样有效,如下例所示:
@Configuration
public class AppConfig {
@Bean
public BeanOne beanOne() {
BeanOne beanOne = new BeanOne();
beanOne.init();
return beanOne;
}
// ...
}
When you work directly in Java, you can do anything you like with your objects and do not always need to rely on the container lifecycle. | |
---|---|
当您直接在 Java 中工作时,您可以对您的对象做任何您喜欢的事情,而不必总是依赖容器生命周期。 |
Specifying Bean Scope
指定 Bean 范围
Spring includes the @Scope
annotation so that you can specify the scope of a bean.
Spring 包含@Scope
注释,以便您可以指定 bean 的范围。
Using the @Scope
Annotation
使用@Scope
注解
You can specify that your beans defined with the @Bean
annotation should have a specific scope. You can use any of the standard scopes specified in the Bean Scopes section.
您可以指定使用@Bean
注释定义的 bean 应具有特定范围。您可以使用 Bean Scopes部分中指定的任何标准范围。
The default scope is singleton
, but you can override this with the @Scope
annotation, as the following example shows:
默认范围是singleton
,但您可以使用@Scope
注释覆盖它,如以下示例所示:
@Configuration
public class MyConfiguration {
@Bean
@Scope("prototype")
public Encryptor encryptor() {
// ...
}
}
@Scope
and scoped-proxy
@Scope和scoped-proxy
Spring offers a convenient way of working with scoped dependencies through scoped proxies. The easiest way to create such a proxy when using the XML configuration is the <aop:scoped-proxy/>
element. Configuring your beans in Java with a @Scope
annotation offers equivalent support with the proxyMode
attribute. The default is ScopedProxyMode.DEFAULT
, which typically indicates that no scoped proxy should be created unless a different default has been configured at the component-scan instruction level. You can specify ScopedProxyMode.TARGET_CLASS
, ScopedProxyMode.INTERFACES
or ScopedProxyMode.NO
.
Spring 提供了一种通过 作用域代理处理作用域依赖的便捷方式。使用 XML 配置时创建此类代理的最简单方法是<aop:scoped-proxy/>
元素。使用注释在 Java 中配置您的 bean提供了对属性@Scope
的等效支持。proxyMode
默认值为ScopedProxyMode.DEFAULT
,这通常表示不应创建作用域代理,除非在组件扫描指令级别配置了不同的默认值。您可以 指定ScopedProxyMode.TARGET_CLASS
或ScopedProxyMode.INTERFACES,ScopedProxyMode.NO
If you port the scoped proxy example from the XML reference documentation (see scoped proxies) to our @Bean
using Java, it resembles the following:
如果您将 XML 参考文档中的作用域代理示例(请参阅 作用域代理)移植到我们@Bean
使用的 Java,它类似于以下内容:
// an HTTP Session-scoped bean exposed as a proxy
@Bean
@SessionScope
public UserPreferences userPreferences() {
return new UserPreferences();
}
@Bean
public Service userService() {
UserService service = new SimpleUserService();
// a reference to the proxied userPreferences bean
service.setUserPreferences(userPreferences());
return service;
}
Customizing Bean Naming
自定义 Bean 命名
By default, configuration classes use a @Bean
method’s name as the name of the resulting bean. This functionality can be overridden, however, with the name
attribute, as the following example shows:
默认情况下,配置类使用@Bean
方法的名称作为生成的 bean 的名称。但是,可以使用name
属性覆盖此功能,如以下示例所示:
@Configuration
public class AppConfig {
@Bean("myThing")
public Thing thing() {
return new Thing();
}
}
Bean Aliasing
Bean 别名
As discussed in Naming Beans, it is sometimes desirable to give a single bean multiple names, otherwise known as bean aliasing. The name
attribute of the @Bean
annotation accepts a String array for this purpose. The following example shows how to set a number of aliases for a bean:
正如命名 Bean中所讨论的,有时需要为单个 bean 提供多个名称,也称为 bean 别名。注释的name
属性@Bean
为此目的接受一个字符串数组。以下示例显示了如何为 bean 设置多个别名:
@Configuration
public class AppConfig {
@Bean({"dataSource", "subsystemA-dataSource", "subsystemB-dataSource"})
public DataSource dataSource() {
// instantiate, configure and return DataSource bean...
}
}
Bean Description
Bean描述
Sometimes, it is helpful to provide a more detailed textual description of a bean. This can be particularly useful when beans are exposed (perhaps through JMX) for monitoring purposes.
有时,提供更详细的 bean 文本描述会很有帮助。当 bean 被暴露(可能通过 JMX)用于监视目的时,这可能特别有用。
To add a description to a @Bean
, you can use the @Description annotation, as the following example shows:
要添加描述@Bean
,您可以使用 @Description 注解,如以下示例所示:
@Configuration
public class AppConfig {
@Bean
@Description("Provides a basic example of a bean")
public Thing thing() {
return new Thing();
}
}
1.12.4. Using the @Configuration
annotation
使用@Configuration
注释
@Configuration
is a class-level annotation indicating that an object is a source of bean definitions. @Configuration
classes declare beans through @Bean
-annotated methods. Calls to @Bean
methods on @Configuration
classes can also be used to define inter-bean dependencies. See Basic Concepts: @Bean and @Configuration for a general introduction.
@Configuration
是一个类级别的注解,表明一个对象是 bean 定义的来源。类通过-annotated 方法@Configuration
声明 bean 。对类上的方法的@Bean
调用也可用于定义 bean 间的依赖关系。请参阅基本概念:@Bean和@Configuration的一般介绍。
Injecting Inter-bean Dependencies
注入 bean 间依赖
When beans have dependencies on one another, expressing that dependency is as simple as having one bean method call another, as the following example shows:
当 bean 相互依赖时,表达这种依赖关系就像让一个 bean 方法调用另一个方法一样简单,如以下示例所示:
@Configuration
public class AppConfig {
@Bean
public BeanOne beanOne() {
return new BeanOne(beanTwo());
}
@Bean
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
In the preceding example, beanOne
receives a reference to beanTwo
through constructor injection.
在前面的示例中,通过构造函数注入beanOne
接收对的引用
This method of declaring inter-bean dependencies works only when the @Bean method is declared within a @Configuration class. You cannot declare inter-bean dependencies by using plain @Component classes. | |
---|---|
这种声明 bean 间依赖关系的方法仅在该@Bean 方法在@Configuration 类中声明时才有效。您不能使用普通@Component 类来声明 bean 间的依赖关系。 |
Lookup Method Injection
查找方法注入
As noted earlier, lookup method injection is an advanced feature that you should use rarely. It is useful in cases where a singleton-scoped bean has a dependency on a prototype-scoped bean. Using Java for this type of configuration provides a natural means for implementing this pattern. The following example shows how to use lookup method injection:
如前所述,查找方法注入是您应该很少使用的高级功能。在单例范围的 bean 依赖于原型范围的 bean 的情况下,它很有用。使用 Java 进行这种类型的配置为实现这种模式提供了一种自然的方式。下面的例子展示了如何使用查找方法注入:
public abstract class CommandManager {
public Object process(Object commandState) {
// grab a new instance of the appropriate Command interface
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
// okay... but where is the implementation of this method?
protected abstract Command createCommand();
}
By using Java configuration, you can create a subclass of CommandManager
where the abstract createCommand()
method is overridden in such a way that it looks up a new (prototype) command object. The following example shows how to do so:
通过使用 Java 配置,您可以创建一个子类,CommandManager
其中抽象createCommand()
方法被覆盖,从而查找新的(原型)命令对象。以下示例显示了如何执行此操作:
@Bean
@Scope("prototype")
public AsyncCommand asyncCommand() {
AsyncCommand command = new AsyncCommand();
// inject dependencies here as required
return command;
}
@Bean
public CommandManager commandManager() {
// return new anonymous implementation of CommandManager with createCommand()
// overridden to return a new prototype Command object
return new CommandManager() {
protected Command createCommand() {
return asyncCommand();
}
}
}
Further Information About How Java-based Configuration Works Internally
有关基于 Java 的配置如何在内部工作的更多信息
Consider the following example, which shows a @Bean
annotated method being called twice:
考虑下面的例子,它显示了一个@Bean
被注解的方法被调用了两次:
@Configuration
public class AppConfig {
@Bean
public ClientService clientService1() {
ClientServiceImpl clientService = new ClientServiceImpl();
clientService.setClientDao(clientDao());
return clientService;
}
@Bean
public ClientService clientService2() {
ClientServiceImpl clientService = new ClientServiceImpl();
clientService.setClientDao(clientDao());
return clientService;
}
@Bean
public ClientDao clientDao() {
return new ClientDaoImpl();
}
}
clientDao()
has been called once in clientService1()
and once in clientService2()
. Since this method creates a new instance of ClientDaoImpl
and returns it, you would normally expect to have two instances (one for each service). That definitely would be problematic: In Spring, instantiated beans have a singleton
scope by default. This is where the magic comes in: All @Configuration
classes are subclassed at startup-time with CGLIB
. In the subclass, the child method checks the container first for any cached (scoped) beans before it calls the parent method and creates a new instance.
clientDao()
已被调用一次clientService1()
和一次clientService2()
。由于此方法会创建一个新实例ClientDaoImpl
并返回它,因此您通常会期望有两个实例(每个服务一个实例)。那肯定会有问题:在 Spring 中,实例化的 beansingleton
默认有一个作用域。这就是神奇之处:所有@Configuration
类在启动时都使用CGLIB
. 在子类中,子方法在调用父方法并创建新实例之前,首先检查容器中是否有任何缓存(作用域)bean。
The behavior could be different according to the scope of your bean. We are talking about singletons here. | |
---|---|
根据 bean 的范围,行为可能会有所不同。我们在这里谈论单例。 |
As of Spring 3.2, it is no longer necessary to add CGLIB to your classpath because CGLIB classes have been repackaged under org.springframework.cglib and included directly within the spring-core JAR. | |
---|---|
从 Spring 3.2 开始,不再需要将 CGLIB 添加到类路径中,因为 CGLIB 类已被重新打包org.springframework.cglib 并直接包含在 spring-core JAR 中。 |
There are a few restrictions due to the fact that CGLIB dynamically adds features at startup-time. In particular, configuration classes must not be final. However, as of 4.3, any constructors are allowed on configuration classes, including the use of @Autowired or a single non-default constructor declaration for default injection.If you prefer to avoid any CGLIB-imposed limitations, consider declaring your @Bean methods on non-@Configuration classes (for example, on plain @Component classes instead). Cross-method calls between @Bean methods are not then intercepted, so you have to exclusively rely on dependency injection at the constructor or method level there. | |
---|---|
由于 CGLIB 在启动时动态添加功能,因此存在一些限制。特别是,配置类不能是最终的。但是,从 4.3 开始,配置类上允许使用任何构造函数,包括使用 @Autowired 或使用单个非默认构造函数声明进行默认注入。如果您希望避免任何 CGLIB 强加的限制,请考虑@Bean 在非@Configuration 类上声明您的方法(例如,@Component 改为在普通类上)。方法之间的跨方法调用@Bean 不会被拦截,因此您必须完全依赖构造函数或方法级别的依赖注入。 |
1.12.5. Composing Java-based Configurations
组合基于 Java 的配置
Spring’s Java-based configuration feature lets you compose annotations, which can reduce the complexity of your configuration.
Spring 的基于 Java 的配置功能允许您编写注解,这可以降低配置的复杂性。
Using the @Import
Annotation
使用@Import
注解
Much as the <import/>
element is used within Spring XML files to aid in modularizing configurations, the @Import
annotation allows for loading @Bean
definitions from another configuration class, as the following example shows:
就像<import/>
在 Spring XML 文件中使用该元素来帮助模块化配置一样,@Import
注释允许@Bean
从另一个配置类加载定义,如以下示例所示:
@Configuration
public class ConfigA {
@Bean
public A a() {
return new A();
}
}
@Configuration
@Import(ConfigA.class)
public class ConfigB {
@Bean
public B b() {
return new B();
}
}
Now, rather than needing to specify both ConfigA.class
and ConfigB.class
when instantiating the context, only ConfigB
needs to be supplied explicitly, as the following example shows:
现在,不需要同时指定ConfigA.class
和ConfigB.class
在实例化上下文时,只ConfigB
需要显式提供,如以下示例所示:
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
// now both beans A and B will be available...
A a = ctx.getBean(A.class);
B b = ctx.getBean(B.class);
}
This approach simplifies container instantiation, as only one class needs to be dealt with, rather than requiring you to remember a potentially large number of @Configuration
classes during construction.
这种方法简化了容器的实例化,因为只需要处理一个类,而不是要求您 @Configuration
在构造过程中记住大量潜在的类。
As of Spring Framework 4.2, @Import also supports references to regular component classes, analogous to the AnnotationConfigApplicationContext.register method. This is particularly useful if you want to avoid component scanning, by using a few configuration classes as entry points to explicitly define all your components. | |
---|---|
从 Spring Framework 4.2 开始,@Import 还支持对常规组件类的引用,类似于AnnotationConfigApplicationContext.register 方法。如果您想通过使用一些配置类作为入口点来显式定义所有组件来避免组件扫描,这将特别有用。 |
Injecting Dependencies on Imported @Bean
Definitions
@Bean
注入对导入定义的依赖
The preceding example works but is simplistic. In most practical scenarios, beans have dependencies on one another across configuration classes. When using XML, this is not an issue, because no compiler is involved, and you can declare ref="someBean"
and trust Spring to work it out during container initialization. When using @Configuration
classes, the Java compiler places constraints on the configuration model, in that references to other beans must be valid Java syntax.
前面的示例有效,但过于简单。在大多数实际场景中,bean 跨配置类相互依赖。使用 XML 时,这不是问题,因为不涉及编译器,您可以声明 ref="someBean"
并信任 Spring 在容器初始化期间解决它。使用@Configuration
类时,Java 编译器对配置模型施加约束,因为对其他 bean 的引用必须是有效的 Java 语法。
Fortunately, solving this problem is simple. As we already discussed, a @Bean
method can have an arbitrary number of parameters that describe the bean dependencies. Consider the following more real-world scenario with several @Configuration
classes, each depending on beans declared in the others:
幸运的是,解决这个问题很简单。正如我们已经讨论过的,一个@Bean
方法可以有任意数量的参数来描述 bean 的依赖关系。考虑以下具有多个@Configuration
类的更真实的场景,每个类都依赖于其他类中声明的 bean:
@Configuration
public class ServiceConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
public class RepositoryConfig {
@Bean
public AccountRepository accountRepository(DataSource dataSource) {
return new JdbcAccountRepository(dataSource);
}
}
@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {
@Bean
public DataSource dataSource() {
// return new DataSource
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
// everything wires up across configuration classes...
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
There is another way to achieve the same result. Remember that @Configuration
classes are ultimately only another bean in the container: This means that they can take advantage of @Autowired
and @Value
injection and other features the same as any other bean.
还有另一种方法可以达到同样的结果。请记住,@Configuration类最终只是容器中的另一个bean:这意味着它们可以利用@Autowired和@Value-injection以及与任何其他bean相同的其他特性。
Make sure that the dependencies you inject that way are of the simplest kind only. @Configuration classes are processed quite early during the initialization of the context, and forcing a dependency to be injected this way may lead to unexpected early initialization. Whenever possible, resort to parameter-based injection, as in the preceding example.Also, be particularly careful with BeanPostProcessor and BeanFactoryPostProcessor definitions through @Bean . Those should usually be declared as static @Bean methods, not triggering the instantiation of their containing configuration class. Otherwise, @Autowired and @Value may not work on the configuration class itself, since it is possible to create it as a bean instance earlier than AutowiredAnnotationBeanPostProcessor. | |
---|---|
确保您以这种方式注入的依赖项只是最简单的类型。@Configuration 类在上下文初始化期间很早就被处理,并且强制以这种方式注入依赖项可能会导致意外的早期初始化。尽可能使用基于参数的注入,如前面的示例所示。此外,请特别注意BeanPostProcessor 和的BeanFactoryPostProcessor 定义@Bean 。这些通常应该被声明为static @Bean 方法,而不是触发它们包含的配置类的实例化。否则,@Autowired 可能@Value 无法在配置类本身上工作,因为可以将其创建为早于 AutowiredAnnotationBeanPostProcessor. |
The following example shows how one bean can be autowired to another bean:
以下示例显示了如何将一个 bean 自动装配到另一个 bean:
@Configuration
public class ServiceConfig {
@Autowired
private AccountRepository accountRepository;
@Bean
public TransferService transferService() {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
public class RepositoryConfig {
private final DataSource dataSource;
public RepositoryConfig(DataSource dataSource) {
this.dataSource = dataSource;
}
@Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(dataSource);
}
}
@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {
@Bean
public DataSource dataSource() {
// return new DataSource
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
// everything wires up across configuration classes...
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
Constructor injection in @Configuration classes is only supported as of Spring Framework 4.3. Note also that there is no need to specify @Autowired if the target bean defines only one constructor. | |
---|---|
@Configuration 仅从 Spring Framework 4.3 开始支持类中的 构造函数注入。@Autowired 另请注意,如果目标 bean 仅定义一个构造函数 ,则无需指定。 |
Fully-qualifying imported beans for ease of navigation
完全合格的进口豆,便于导航
In the preceding scenario, using @Autowired
works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig
, how do you know exactly where the @Autowired AccountRepository
bean is declared? It is not explicit in the code, and this may be just fine. Remember that the Spring Tools for Eclipse provides tooling that can render graphs showing how everything is wired, which may be all you need. Also, your Java IDE can easily find all declarations and uses of the AccountRepository
type and quickly show you the location of @Bean
methods that return that type.
在前面的场景中,using@Autowired
运行良好并提供了所需的模块化,但确定自动装配 bean 定义的确切声明位置仍然有些模棱两可。例如,作为开发人员ServiceConfig
,您如何知道@Autowired AccountRepository
bean 的确切声明位置?它在代码中并不明确,这可能很好。请记住, Eclipse 的 Spring Tools提供的工具可以渲染显示所有连接方式的图形,这可能就是您所需要的。此外,您的 Java IDE 可以轻松找到该AccountRepository
类型的所有声明和使用,并快速向您显示@Bean
返回该类型的方法的位置。
In cases where this ambiguity is not acceptable and you wish to have direct navigation from within your IDE from one @Configuration
class to another, consider autowiring the configuration classes themselves. The following example shows how to do so:
如果这种歧义是不可接受的,并且您希望在 IDE 中从一个@Configuration
类直接导航到另一个类,请考虑自动装配配置类本身。以下示例显示了如何执行此操作:
@Configuration
public class ServiceConfig {
@Autowired
private RepositoryConfig repositoryConfig;
@Bean
public TransferService transferService() {
// navigate 'through' the config class to the @Bean method!
return new TransferServiceImpl(repositoryConfig.accountRepository());
}
}
In the preceding situation, where AccountRepository
is defined is completely explicit. However, ServiceConfig
is now tightly coupled to RepositoryConfig
. That is the tradeoff. This tight coupling can be somewhat mitigated by using interface-based or abstract class-based @Configuration
classes. Consider the following example:
在上述情况下,where AccountRepository
is defined 是完全明确的。但是,ServiceConfig
现在与RepositoryConfig
. 这就是权衡。通过使用基于接口或基于抽象类的类可以在一定程度上缓解这种紧密耦合@Configuration
。考虑以下示例:
@Configuration
public class ServiceConfig {
@Autowired
private RepositoryConfig repositoryConfig;
@Bean
public TransferService transferService() {
return new TransferServiceImpl(repositoryConfig.accountRepository());
}
}
@Configuration
public interface RepositoryConfig {
@Bean
AccountRepository accountRepository();
}
@Configuration
public class DefaultRepositoryConfig implements RepositoryConfig {
@Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(...);
}
}
@Configuration
@Import({ServiceConfig.class, DefaultRepositoryConfig.class}) // import the concrete config!
public class SystemTestConfig {
@Bean
public DataSource dataSource() {
// return DataSource
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
Now ServiceConfig
is loosely coupled with respect to the concrete DefaultRepositoryConfig
, and built-in IDE tooling is still useful: You can easily get a type hierarchy of RepositoryConfig
implementations. In this way, navigating @Configuration
classes and their dependencies becomes no different than the usual process of navigating interface-based code.
NowServiceConfig
相对于具体的 是松散耦合的 DefaultRepositoryConfig
,并且内置的 IDE 工具仍然有用:您可以轻松获得RepositoryConfig
实现的类型层次结构。通过这种方式,导航@Configuration
类及其依赖项与导航基于接口的代码的通常过程没有什么不同。
If you want to influence the startup creation order of certain beans, consider declaring some of them as @Lazy (for creation on first access instead of on startup) or as @DependsOn certain other beans (making sure that specific other beans are created before the current bean, beyond what the latter’s direct dependencies imply). | |
---|---|
如果您想影响某些 bean 的启动创建顺序,请考虑将其中一些声明为@Lazy (用于在首次访问时创建而不是在启动时创建)或@DependsOn 某些其他 bean(确保在当前 bean 之前创建特定的其他 bean,超出后者的直接依赖意味着什么)。 |
Conditionally Include @Configuration
Classes or @Bean
Methods
有条件地包含@Configuration
类或@Bean
方法
It is often useful to conditionally enable or disable a complete @Configuration
class or even individual @Bean
methods, based on some arbitrary system state. One common example of this is to use the @Profile
annotation to activate beans only when a specific profile has been enabled in the Spring Environment
(see Bean Definition Profiles for details).
基于某些任意系统状态,有条件地启用或禁用完整的@Configuration
类甚至单个方法通常很有用。@Bean
一个常见的例子是,@Profile
只有在 Spring 中启用了特定配置文件时才使用注解来激活 bean Environment
(有关详细信息,请参阅Bean 定义配置文件 )。
The @Profile
annotation is actually implemented by using a much more flexible annotation called @Conditional. The @Conditional
annotation indicates specific org.springframework.context.annotation.Condition
implementations that should be consulted before a @Bean
is registered.
@Profile
注释实际上是通过使用更灵活的注释来实现的,称为@Conditional. @Conditional
注释指示 在注册org.springframework.context.annotation.Condition
a 之前应参考的具体实现@Bean
。
Implementations of the Condition
interface provide a matches(…)
method that returns true
or false
. For example, the following listing shows the actual Condition
implementation used for @Profile
:
接口的实现Condition
提供了一个matches(…)
返回true
或的方法false
。例如,以下清单显示了 Condition
用于 的实际实现@Profile
:
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// Read the @Profile annotation attributes
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs != null) {
for (Object value : attrs.get("value")) {
if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
return true;
}
}
return false;
}
return true;
}
See the @Conditional javadoc for more detail.
有关更多详细信息,请参阅@Conditional javadoc。
Combining Java and XML Configuration
结合 Java 和 XML 配置
Spring’s @Configuration
class support does not aim to be a 100% complete replacement for Spring XML. Some facilities, such as Spring XML namespaces, remain an ideal way to configure the container. In cases where XML is convenient or necessary, you have a choice: either instantiate the container in an “XML-centric” way by using, for example, ClassPathXmlApplicationContext
, or instantiate it in a “Java-centric” way by using AnnotationConfigApplicationContext
and the @ImportResource
annotation to import XML as needed.
Spring 的@Configuration
类支持并非旨在 100% 完全替代 Spring XML。一些工具,例如 Spring XML 命名空间,仍然是配置容器的理想方式。在 XML 方便或必要的情况下,您可以选择:或者以“以 XML 为中心”的方式实例化容器,例如使用 , ClassPathXmlApplicationContext
或者以“以 Java 为中心”的方式实例化它 AnnotationConfigApplicationContext
,@ImportResource
使用根据需要导入 XML。
XML-centric Use of @Configuration
Classes
以 XML 为中心的@Configuration
类的使用
It may be preferable to bootstrap the Spring container from XML and include @Configuration
classes in an ad-hoc fashion. For example, in a large existing codebase that uses Spring XML, it is easier to create @Configuration
classes on an as-needed basis and include them from the existing XML files. Later in this section, we cover the options for using @Configuration
classes in this kind of “XML-centric” situation.
最好从 XML 引导 Spring 容器并 @Configuration
以特别的方式包含类。例如,在使用 Spring XML 的大型现有代码库中,更容易根据@Configuration
需要创建类并从现有 XML 文件中包含它们。在本节的后面部分,我们将介绍@Configuration
在这种“以 XML 为中心”的情况下使用类的选项。
Declaring @Configuration
classes as plain Spring <bean/>
elements
将类声明@Configuration
为普通 Spring<bean/>
元素
Remember that @Configuration
classes are ultimately bean definitions in the container. In this series examples, we create a @Configuration
class named AppConfig
and include it within system-test-config.xml
as a <bean/>
definition. Because <context:annotation-config/>
is switched on, the container recognizes the @Configuration
annotation and processes the @Bean
methods declared in AppConfig
properly.
请记住,@Configuration
类最终是容器中的 bean 定义。在本系列示例中,我们创建了一个@Configuration
名为的类AppConfig
,并将其system-test-config.xml
作为<bean/>
定义包含在其中。因为 <context:annotation-config/>
是开启的,所以容器会识别 @Configuration
注解并正确处理其中@Bean
声明的方法AppConfig
。
The following example shows an ordinary configuration class in Java:
以下示例显示了 Java 中的一个普通配置类:
@Configuration
public class AppConfig {
@Autowired
private DataSource dataSource;
@Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(dataSource);
}
@Bean
public TransferService transferService() {
return new TransferService(accountRepository());
}
}
The following example shows part of a sample system-test-config.xml
file:
以下示例显示了示例system-test-config.xml
文件的一部分:
<beans>
<!-- enable processing of annotations such as @Autowired and @Configuration -->
<context:annotation-config/>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
<bean class="com.acme.AppConfig"/>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
The following example shows a possible jdbc.properties
file:
以下示例显示了一个可能的jdbc.properties
文件
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml");
TransferService transferService = ctx.getBean(TransferService.class);
// ...
}
In system-test-config.xml file, the AppConfig <bean/> does not declare an id element. While it would be acceptable to do so, it is unnecessary, given that no other bean ever refers to it, and it is unlikely to be explicitly fetched from the container by name. Similarly, the DataSource bean is only ever autowired by type, so an explicit bean id is not strictly required. | |
---|---|
在system-test-config.xml 文件中,AppConfig <bean/> 不声明id 元素。虽然这样做是可以接受的,但这是不必要的,因为没有其他 bean 曾经引用过它,并且不太可能通过名称从容器中显式获取。类似地,DataSource bean 仅按类型自动装配,因此id 并不严格要求显式 bean。 |
Using context:component-scan/ to pick up @Configuration
classes
使用 context:component-scan/ 拾取@Configuration
类
Because @Configuration
is meta-annotated with @Component
, @Configuration
-annotated classes are automatically candidates for component scanning. Using the same scenario as describe in the previous example, we can redefine system-test-config.xml
to take advantage of component-scanning. Note that, in this case, we need not explicitly declare <context:annotation-config/>
, because <context:component-scan/>
enables the same functionality.
因为@Configuration
是用 元注释的@Component
,带注释的@Configuration
类自动成为组件扫描的候选对象。使用与前面示例中描述的相同场景,我们可以重新定义system-test-config.xml
以利用组件扫描。请注意,在这种情况下,我们不需要显式声明 <context:annotation-config/>
,因为<context:component-scan/>
启用了相同的功能。
The following example shows the modified system-test-config.xml
file:
以下示例显示了修改后的system-test-config.xml
文件:
<beans>
<!-- picks up and registers AppConfig as a bean definition -->
<context:component-scan base-package="com.acme"/>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
@Configuration
Class-centric Use of XML with @ImportResource
@Configuration以类为中心使用 XML@ImportResource
In applications where @Configuration
classes are the primary mechanism for configuring the container, it is still likely necessary to use at least some XML. In these scenarios, you can use @ImportResource
and define only as much XML as you need. Doing so achieves a “Java-centric” approach to configuring the container and keeps XML to a bare minimum. The following example (which includes a configuration class, an XML file that defines a bean, a properties file, and the main
class) shows how to use the @ImportResource
annotation to achieve “Java-centric” configuration that uses XML as needed:
在@Configuration
类是配置容器的主要机制的应用程序中,仍然可能至少需要使用一些 XML。在这些场景中,您可以根据@ImportResource
需要使用和定义尽可能多的 XML。这样做实现了一种“以 Java 为中心”的方法来配置容器并将 XML 保持在最低限度。以下示例(包括配置类、定义 bean 的 XML 文件、属性文件和main
类)显示了如何使用@ImportResource
注解来实现“以 Java 为中心”的配置,该配置根据需要使用 XML:
@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
public class AppConfig {
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource() {
return new DriverManagerDataSource(url, username, password);
}
}
properties-config.xml
<beans>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
</beans>
jdbc.properties jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
TransferService transferService = ctx.getBean(TransferService.class);
// ...
}