[译]Spring中@Configuration和@Component的对比
本文翻译自Spring @Configuration vs @Component。
在前一篇文章中,我说过我们可以使用@Component
作为@Configuration
的一个备用选择,实际上这是来自于Spring team的官方建议
也就是说,
@Bean
在我们不使用任何CGLIB
代理时有一种精简模式:只需在未使用@Configuration
注释的类上声明@Bean
方法(但通常需要用另一种Spring
中的stereotype实现替代,如@Component
),只要我们不在 @Bean 方法之间进行编程调用,程序就能正常工作。
简而言之,下面显示的每个应用程序上下文配置将以完全不同的方式来生效:
@Configuration
public static class Config {
@Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
@Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean());
}
}
@Component
public static class Config {
@Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
@Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean());
}
}
第一段代码能按照预期正常工作,SimpleBeanConsumer
将获取一个指向SimpleBean
单例的链接,不幸的是,该段代码在Java数字签名环境中不生效。
第二个代码则是完全不正确的,因为Spring
会创建SimpleBean
的单例bean,但是SimpleBeanConsumer
会获得另一个SimpleBean
实例,该实例不受Spring
上下文控制。
此现象的原因解释如下:
如果使用@Configuration
,则所有标记为@Bean
的方法都将被包装到CGLIB
包装器中,该包装器的工作方式为该方法第一次调用时将执行原始方法的主体,并将生成的对象注册在Spring
上下文中,之后对该方法的调用都只返回从Spring
上下文中获取到的bean。
在上面的第二个代码块中,new SimpleBeanConsumer(simpleBean())
只是调用一个纯java方法调用,要更正该代码块,可修改如下:
@Component
public static class Config {
@Autowired
SimpleBean simpleBean;
@Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
@Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean);
}
}
这篇文章的所有代码示例都可以在我的个人GitHub中找到。