@Bean
是一个方法级的注解,它与XML中的类似。 注解支持<bean/>
提供的一些属性,例如:init-method, destroy-method, autowiring和name
。
可以在@Configuration或@Component注解的类中使用@Bean注解。
要声明一个bean,只需使用@Bean
注解一个方法。使用此方法,将会在ApplicationContext
内注册一个bean,bean的类型是方法的返回值类型。 默认情况下,bean名称将与方法名称相同。 下面是一个简单的例子:@Bean
方法声明:
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
上面的配置完全等同于以下Spring XML:
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
两种方式都定义了一个名字为transferService
的bean,且绑定了TransferServiceImpl
的实例:
transferService -> com.acme.TransferServiceImpl
一个@Bean
注解的方法可以有任意数量的参数描述构建该bean所需的依赖。 例如,如果我们的TransferService
需要一个AccountRepository
,我们可以通过一个方法参数来实现该依赖:
@Configuration
public class AppConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
解析机制与基于构造函数的依赖注入非常相似,参见相关部分 。
使用@Bean
注解定义的任何类都支持常规的生命周期回调,并且可以使用JSR-250的@PostConstruct
和@PreDestroy
注解,参见JSR-250注解 。
完全支持常规Spring lifecycle回调。如果bean实现了InitializingBean, DisposableBean, or Lifecycle
,它们各自的方法由容器调用。
同样地,标准的*Aware
接口,如 BeanFactoryAware, BeanNameAware, MessageSourceAware, ApplicationContextAware等等都完全支持。
@Bean
注解支持指定任意初始化和销毁回调方法,就像Spring XML的bean
元素的init-method
和destroy-method
属性:
public class Foo {
public void init() {
// initialization logic
}
}
public class Bar {
public void cleanup() {
// destruction logic
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public Foo foo() {
return new Foo();
}
@Bean(destroyMethod = "cleanup")
public Bar bar() {
return new Bar();
}
}
默认情况下,使用java config定义的bean中
close
方法或者shutdown
方法,会作为销毁回调自动调用。
若bean中有close
,shutdown
方法,又不是销毁回调,通过设置@Bean(destroyMethod="")
,即可关闭该默认的自动匹配销毁回调模式。
你可能希望对通过JNDI获取的资源执行此操作,因为它的生命周期是在应用程序外部管理的。尤其是,使用DataSource
时一定要关闭它,不关会有问题。@Bean(destroyMethod="") public DataSource dataSource() throws NamingException { return (DataSource) jndiTemplate.lookup("MyDS"); }同样地,,使用
@Bean
方法,通常会选择使用程序化的JNDI查找:使用Spring的JndiTemplate
/JndiLocatorDelegate
帮助类或直接使用JNDI的InitialContext但是不要使用JndiObjectFactoryBean
变体,因为它会强制你去声明一个返回类型作为FactoryBean的类型代替实际的目标类型,这会使得交叉引用变得很困难。
当然,上面Foo
的例子中,也可以在构造函数中调用init()
方法,和上面例子中的效果相同;
@Configuration
public class AppConfig {
@Bean
public Foo foo() {
Foo foo = new Foo();
foo.init();
return foo;
}
// ...
}
如果是直接使用java,对于对象,你想怎么搞就怎么搞,并不总需要依赖容器生命周期! |
可以使用任何标准的方式为@Bean
注解的bean指定一个作用域。 你可以使用Bean Scopes章节中的任意标准作用域。
默认范围是singleton
,但是你可以使用@Scope
注解来覆盖它:
@Configuration
public class MyConfiguration {
@Bean
@Scope("prototype")
public Encryptor encryptor() {
// ...
}
}
Spring通过scoped代理提供了一种方便的方式完成作用域bean依赖关系。 在使用XML配置时创建这种代理的最简单的方法是<aop:scoped-proxy/>
元素。 若是在Java代码中配置bean,有一种等价的做法,使用@Scope
注解并配置其proxyMOde
属性. 默认是没有代理(ScopedProxyMode.NO
),但你可以指定ScopedProxyMode.TARGET_CLASS
或ScopedProxyMode.INTERFACES
。
如果将XML格式的作用域代理示例转换成Java中使用@Bean
,差不多是这样:
// 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;
}
默认情况下,配置类中,使用@Bean
的方法名作为返回bean的名字。 但是,使用name
属性可以覆盖此功能。
@Configuration
public class AppConfig {
@Bean(name = "myFoo")
public Foo foo() {
return new Foo();
}
}
如第3.3.1节“命名bean”中所讨论的有时候需要给一个bean指定多个name。@Bean
注解的name
属性就是干这个用的,该属性接收一个字串数组。
@Configuration
public class AppConfig {
@Bean(name = { "dataSource", "subsystemA-dataSource", "subsystemB-dataSource" })
public DataSource dataSource() {
// instantiate, configure and return DataSource bean...
}
}
有时,提供bean的更详细的文本描述是有帮助的。 用于监视目的(通过JMX)的时候,这可能特别有用。
要向一个@Bean
添加一个描述 ,可以使用@Description
注解:
@Configuration
public class AppConfig {
@Bean
@Description("Provides a basic example of a bean")
public Foo foo() {
return new Foo();
}
}