使用@Bean
注解
@Bean
是一个方法级别的注解,直接对应XML中的<bean/>
元素。该注解支持<bean/>
提供的一些属性,例如:
您可以在@Configuration
注解或@Component
注解的类中使用@Bean
注解。
声明一个Bean
@Bean
注解对方法进行注解。您可以使用此方法在
ApplicationContext
中注册与方法返回值指定类型的bean定义。默认情况下,bean名称与方法名称相同。以下示例显示了一个
@Bean
方法声明:
-
Java
-
Kotlin
@Configuration
public class AppConfig {
@Bean
public TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
@Configuration
class AppConfig {
@Bean
fun transferService() = TransferServiceImpl()
}
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
transferService
的bean在
ApplicationContext
中可用,绑定到类型为
TransferServiceImpl
的对象实例,如下文所示:
transferService -> com.acme.TransferServiceImpl
-
Java
public interface BaseConfig {
@Bean
default TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
@Configuration
public class AppConfig implements BaseConfig {
}
@Bean
方法声明为接口(或基类)返回类型,如下例所示:
-
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被实例化后才解析)。
如果您始终通过声明的服务接口引用类型,您的@Bean 返回类型可以安全地遵循该设计决策。但是,对于实现多个接口的组件或可能按其实现类型引用的组件,最好声明尽可能具体的返回类型(至少与引用您的bean的注入点要求的一样具体)。 |
Bean依赖关系
@Bean
注解的方法可以有任意数量的参数,描述构建该bean所需的依赖关系。例如,如果我们的
TransferService
需要一个
AccountRepository
,我们可以通过方法参数实现该依赖关系,如下例所示:
-
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)
}
}
相关部分。
接收生命周期回调
任何使用@Bean
注解定义的类都支持常规的生命周期回调,并可以使用JSR-250中的@PostConstruct
和@PreDestroy
注解。有关详细信息,请参见JSR-250注解。
常规的Spring生命周期回调也得到充分支持。如果一个bean实现了InitializingBean
、DisposableBean
或Lifecycle
,则容器会调用它们各自的方法。
标准的*Aware
接口集(如BeanFactoryAware、BeanNameAware、MessageSourceAware、ApplicationContextAware等)也得到充分支持。
@Bean
注解支持指定任意的初始化和销毁回调方法,类似于Spring XML中bean
元素上的init-method
和destroy-method
属性,如下例所示:
-
Java
-
Kotlin
public class BeanOne {
public void init() {
// 初始化逻辑
}
}
public class BeanTwo {
public void cleanup() {
// 销毁逻辑
}
}
@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() {
// 初始化逻辑
}
}
class BeanTwo {
fun cleanup() {
// 销毁逻辑
}
}
@Configuration
class AppConfig {
@Bean(initMethod = "init")
fun beanOne() = BeanOne()
@Bean(destroyMethod = "cleanup")
fun beanTwo() = BeanTwo()
}
默认情况下,使用Java配置定义的bean如果具有公共的 您可能希望对通过JNDI获取的资源默认执行此操作,因为其生命周期在应用程序之外进行管理。特别是,确保始终对 以下示例显示了如何防止
此外,在 |
在上面示例中的BeanOne
的情况下,也可以在构造过程中直接调用init()
方法,如下例所示:
-
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中工作时,您可以随意处理对象,不一定总是依赖容器的生命周期。 |
指定Bean作用域
Spring包含@Scope
注解,以便您可以指定bean的作用域。
使用@Scope
注解
您可以指定使用@Bean
注解定义的bean应具有特定的作用域。您可以使用Bean作用域部分中指定的任何标准作用域。
默认作用域是singleton
,但您可以使用@Scope
注解覆盖此设置,如下例所示:
-
Java
-
Kotlin
@Configuration
public class MyConfiguration {
@Bean
@Scope("prototype")
public Encryptor encryptor() {
// ...
}
}
@Configuration
class MyConfiguration {
@Bean
@Scope("prototype")
fun encryptor(): Encryptor {
// ...
}
}
@Scope
和scoped-proxy
Spring通过作用域代理为使用作用域的依赖项提供了一种方便的工作方式。在使用XML配置时创建这样的代理的最简单方法是使用<aop:scoped-proxy/>
元素。在Java中使用@Scope
注解配置bean提供了与proxyMode
属性等效的支持。默认值为ScopedProxyMode.DEFAULT
,通常表示除非在组件扫描指令级别配置了不同的默认值,否则不应创建作用域代理。您可以指定ScopedProxyMode.TARGET_CLASS
、ScopedProxyMode.INTERFACES
或ScopedProxyMode.NO
。
如果您将XML参考文档中的作用域代理示例(请参阅作用域代理)转换为使用Java的@Bean
,则如下所示:
-
Java
-
Kotlin
// 作为代理公开的HTTP会话作用域bean
@Bean
@SessionScope
public UserPreferences userPreferences() {
return new UserPreferences();
}
@Bean
public Service userService() {
UserService service = new SimpleUserService();
// 对代理的userPreferences bean的引用
service.setUserPreferences(userPreferences());
return service;
}
// 作为代理公开的HTTP会话作用域bean
@Bean
@SessionScope
fun userPreferences() = UserPreferences()
@Bean
fun userService(): Service {
return SimpleUserService().apply {
// 对代理的userPreferences bean的引用
setUserPreferences(userPreferences())
}
}
自定义Bean命名
默认情况下,配置类使用@Bean
方法的名称作为生成的bean的名称。但是,可以使用name
属性覆盖此功能,如下例所示:
-
Java
-
Kotlin
@Configuration
public class AppConfig {
@Bean("myThing")
public Thing thing() {
return new Thing();
}
}
@Configuration
class AppConfig {
@Bean("myThing")
fun thing() = Thing()
}
Bean别名
如在命名Beans中所讨论的,有时希望给单个bean提供多个名称,也就是所谓的bean别名。@Bean
注解的name
属性接受一个String数组以实现此目的。以下示例显示了如何为bean设置多个别名:
-
Java
-
Kotlin
@Configuration
public class AppConfig {
@Bean({"dataSource", "subsystemA-dataSource", "subsystemB-dataSource"})
public DataSource dataSource() {
// 实例化、配置和返回DataSource bean...
}
}
@Configuration
class AppConfig {
@Bean("dataSource", "subsystemA-dataSource", "subsystemB-dataSource")
fun dataSource(): DataSource {
// 实例化、配置和返回DataSource bean...
}
}
Bean描述
有时,为bean提供更详细的文本描述是有帮助的。当bean被暴露(可能通过JMX)用于监控目的时,这可能特别有用。
要为@Bean
添加描述,您可以使用@Description
注解,如下例所示:
-
Java
-
Kotlin
@Configuration
public class AppConfig {
@Bean
@Description("提供一个bean的基本示例")
public Thing thing() {
return new Thing();
}
}
@Configuration
class AppConfig {
@Bean
@Description("提供一个bean的基本示例")
fun thing() = Thing()
}