Using the @Bean
Annotation
@Bean
是一个方法级注释,并且是 XML <bean/>
元素的直接类比。此注释支持 <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:
您可以在带 @Configuration
注释的类或带 @Component
注释的类中使用 @Bean
注释。
You can use the @Bean
annotation in a @Configuration
-annotated or in a
@Component
-annotated class.
Declaring a Bean
要声明 Bean,可以用 @Bean
注释注释某个方法。您可以使用此方法在指定为方法返回值的类型的 ApplicationContext
中注册 Bean 定义。默认情况下,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:
-
Java
-
Kotlin
@Configuration
public class AppConfig {
@Bean
public TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
@Configuration
class AppConfig {
@Bean
fun transferService() = TransferServiceImpl()
}
前面的配置与以下 Spring XML 完全等效:
The preceding configuration is exactly equivalent to the following Spring XML:
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
这两个声明都可以在 ApplicationContext
中使用名为 transferService
的 Bean,该 Bean 绑定到类型为 TransferServiceImpl
的对象实例,如下面文本图像所示:
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:
transferService -> com.acme.TransferServiceImpl
您还可以使用默认方法定义 Bean。这样可以通过实现带有默认方法上 Bean 定义的界面来组合 Bean 配置。
You can also use default methods to define beans. This allows composition of bean configurations by implementing interfaces with bean definitions on default methods.
-
Java
public interface BaseConfig {
@Bean
default TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
@Configuration
public class AppConfig implements BaseConfig {
}
您还可以使用界面(或基类)返回类型声明 @Bean
方法,如下面的示例所示:
You can also declare your @Bean
method with an interface (or base class)
return type, as the following example shows:
-
Java
-
Kotlin
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
@Configuration
class AppConfig {
@Bean
fun transferService(): TransferService {
return TransferServiceImpl()
}
}
但是,这会将高级类型预测的可见性限制为指定接口类型(TransferService
)。然后,容器仅在实例化受影响的单例 Bean 之后才知道完整类型(TransferServiceImpl
)。非懒惰单例 Bean 会根据其声明顺序进行实例化,因此当其他组件尝试按非声明类型进行匹配时,您可能会看到不同的类型匹配结果(比如 @Autowired TransferServiceImpl
,它只有在 transferService
Bean 实例化之后才会解析)。
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).
如果你持续用声明的服务接口来引用你的类型,你的`@Bean` 返回类型可以安全地加入那个设计决策。但是,对于实现多个接口的组件或可能被其实现类型引用的组件,声明尽可能最具体的返回类型更加安全(至少要和引用你的 bean 的注入点要求的一样具体)。 |
If you consistently refer to your types by a declared service interface, your
|
Bean Dependencies
使用 @Bean
注释的方法可以具有任意数量的参数,这些参数描述生成该 Bean 所需的依赖项。例如,如果我们的 TransferService
需要一个 AccountRepository
,我们就可以使用一个方法参数将该依赖项具象化,如下面的示例所示:
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:
-
Java
-
Kotlin
@Configuration
public class AppConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
class AppConfig {
@Bean
fun transferService(accountRepository: AccountRepository): TransferService {
return TransferServiceImpl(accountRepository)
}
}
解析机制与基于构造函数的依赖注入非常相似。有关更多详情,请参见 the relevant section。
The resolution mechanism is pretty much identical to constructor-based dependency injection. See the relevant section for more details.
Receiving Lifecycle Callbacks
使用 @Bean
注释定义的所有类都支持常规生命周期回调,并且可以使用 JSR-250 中的 @PostConstruct
和 @PreDestroy
注释。请参阅 JSR-250 注释,了解更多详细信息。
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.
常规 Springlifecycle 回调也得到完全支持。如果某个 Bean 实施 InitializingBean
、DisposableBean
或 Lifecycle
,则容器会调用它们各自的方法。
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.
标准的 *Aware
接口集(如 BeanFactoryAware、BeanNameAware、MessageSourceAware、ApplicationContextAware 等)也受到完全支持。
The standard set of *Aware
interfaces (such as BeanFactoryAware,
BeanNameAware,
MessageSourceAware,
ApplicationContextAware, and so on) are also fully supported.
@Bean
注解支持指定任意初始化和销毁回调方法,这与 Spring XML 的 bean
元素上的 init-method
和 destroy-method
属性非常相似,如下例所示:
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:
-
Java
-
Kotlin
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();
}
}
class BeanOne {
fun init() {
// initialization logic
}
}
class BeanTwo {
fun cleanup() {
// destruction logic
}
}
@Configuration
class AppConfig {
@Bean(initMethod = "init")
fun beanOne() = BeanOne()
@Bean(destroyMethod = "cleanup")
fun beanTwo() = BeanTwo()
}
默认情况下,使用 Java 配置定义的拥有公共 By default, beans defined with Java configuration that have a public 您可能希望对使用 JNDI 获取的资源默认这么做,因为它的生命周期在应用程序外部管理。尤其请务必始终对 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 以下示例演示了如何防止对 The following example shows how to prevent an automatic destruction callback for a
|
- Java
-
@Bean(destroyMethod = "") public DataSource dataSource() throws NamingException { return (DataSource) jndiTemplate.lookup("MyDS"); }
- Kotlin
-
@Bean(destroyMethod = "") fun dataSource(): DataSource { return jndiTemplate.lookup("MyDS") as DataSource }
另外,使用 @Bean
方法通常通过使用 Spring 的 JndiTemplate
或 JndiLocatorDelegate
帮助器或直接使用 JNDI InitialContext
,但不能使用 JndiObjectFactoryBean
变体(这将强迫您将返回类型声明为 FactoryBean
类型,而不是实际目标类型,这将使其更难用于其他 @Bean
方法中的交叉引用调用,这些方法旨在引用此处提供的资源)。
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).
对于上述示例中的 BeanOne
,在构建过程中直接调用 init()
方法也是同样有效的,如下例所示:
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:
-
Java
-
Kotlin
@Configuration
public class AppConfig {
@Bean
public BeanOne beanOne() {
BeanOne beanOne = new BeanOne();
beanOne.init();
return beanOne;
}
// ...
}
@Configuration
class AppConfig {
@Bean
fun beanOne() = BeanOne().apply {
init()
}
// ...
}
当你直接在 Java 中工作时,你可以对你的对象做任何你喜欢的事,并且并不总需要依赖于容器生命周期。 |
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. |
Specifying Bean Scope
Spring 包含 @Scope
注解,以便您可以指定 bean 的作用域。
Spring includes the @Scope
annotation so that you can specify the scope of a bean.
Using the @Scope
Annotation
您可以指定使用 @Bean
注解定义的 Bean 应具有特定范围。您可以在 Bean Scopes 部分中指定任何标准范围。
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.
默认作用域是 singleton
,但您可以根据需要使用 @Scope
注解覆盖它,如下例所示:
The default scope is singleton
, but you can override this with the @Scope
annotation,
as the following example shows:
-
Java
-
Kotlin
@Configuration
public class MyConfiguration {
@Bean
@Scope("prototype")
public Encryptor encryptor() {
// ...
}
}
@Configuration
class MyConfiguration {
@Bean
@Scope("prototype")
fun encryptor(): Encryptor {
// ...
}
}
@Scope
and scoped-proxy
Spring 通过 scoped proxies 提供了一种处理作用域依赖项的便利方式。在使用 XML 配置时创建此类代理的最简单方法是使用 <aop:scoped-proxy/>
元素。使用 @Scope
注释在 Java 中配置 bean 可通过 proxyMode
属性提供同等支持。默认值为 ScopedProxyMode.DEFAULT
,它通常表示不应创建作用域代理,除非已在组件扫描指令级别配置了不同的默认值。你可以指定 ScopedProxyMode.TARGET_CLASS
、ScopedProxyMode.INTERFACES
或 ScopedProxyMode.NO
。
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
.
如果你将 XML 参考文档中的作用域代理示例(参见 scoped proxies)移植到我们的 @Bean
中并使用 Java,它类似于以下内容:
If you port the scoped proxy example from the XML reference documentation (see
scoped proxies) to our @Bean
using Java,
it resembles the following:
-
Java
-
Kotlin
// 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;
}
// an HTTP Session-scoped bean exposed as a proxy
@Bean
@SessionScope
fun userPreferences() = UserPreferences()
@Bean
fun userService(): Service {
return SimpleUserService().apply {
// a reference to the proxied userPreferences bean
setUserPreferences(userPreferences())
}
}
Customizing Bean Naming
默认情况下,配置类以 @Bean
方法的名称作为结果 bean 的名称。但是,可以使用 name
属性覆盖此功能,如下例所示:
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:
-
Java
-
Kotlin
@Configuration
public class AppConfig {
@Bean("myThing")
public Thing thing() {
return new Thing();
}
}
@Configuration
class AppConfig {
@Bean("myThing")
fun thing() = Thing()
}
Bean Aliasing
如 Naming Beans 所述,有时需要给单个 bean 多个名称(也称为 bean 别名)。为此,@Bean
注释的 name
属性接受一个 String 数组。以下示例展示了如何为 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:
-
Java
-
Kotlin
@Configuration
public class AppConfig {
@Bean({"dataSource", "subsystemA-dataSource", "subsystemB-dataSource"})
public DataSource dataSource() {
// instantiate, configure and return DataSource bean...
}
}
@Configuration
class AppConfig {
@Bean("dataSource", "subsystemA-dataSource", "subsystemB-dataSource")
fun dataSource(): DataSource {
// instantiate, configure and return DataSource bean...
}
}
Bean Description
有时,提供 bean 的更详细文本描述会很有用。当 bean(可能通过 JMX)暴露出于监视目的时,这可能会特别有用。
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
添加描述,可以使用 @Description
注解,如下例所示:
To add a description to a @Bean
, you can use the
@Description
annotation, as the following example shows:
-
Java
-
Kotlin
@Configuration
public class AppConfig {
@Bean
@Description("Provides a basic example of a bean")
public Thing thing() {
return new Thing();
}
}
@Configuration
class AppConfig {
@Bean
@Description("Provides a basic example of a bean")
fun thing() = Thing()
}