我正在学习 Spring Core 认证,我对基于学习 Material 的这个问题的答案有一些疑问。
Why are you not allowed to annotate a final class with @Configuration
我的推理是为了证实这个断言:
考虑以下配置类:
@Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository();
}
@Bean
public TransferService transferService() {
TransferServiceImpl service = new TransferServiceImpl();
service.setAccountRepository(accountRepository());
return service;
}
@Bean
public AccountService accountService() {
return new AccountServiceImpl(accountRepository());
}
乍一看,这种情况可能看起来很奇怪,因为第一个方法 (accountRepository()) 将 JdbcAccountRepository 对象实例化为具有 id=AccountRepository的 bean strong> 遵循 Spring 默认行为,是一个 singleton
第二个和第三个方法调用 两次 accountRepository() 方法应该再实例化两次 JdbcAccountRepository 对象,而这不是可能是因为它是单例的!!!
因此,为了解决这种情况,Spring 使用 基于继承的代理 策略来创建我的配置类的子类(由 注释的@Configuration) 确实如此:
对于每个 bean,在子类中缓存一个实例
子类只在第一次实例化时调用 super
所以子类是入口点,因为这个子类实现了以下行为:
公共(public)类 AppConfig$$EnhancerByCGLIB$ 扩展 AppConfig {
public AccountRepository accountRepository() {
// if bean is in the applicationContext
// return bean
// else call super.accountRepository() and store bean in context
}
public TransferService transferService() {
// if bean is in the applicationContext, return bean
// else call super.transferService() and store bean in context
}
.....................................................
.....................................................
.....................................................
}
因此,如果我用 final 注释配置类,Spring 就不能有这种行为,因为在 Java 中 final 类不能被子类化
对吗?
使用相同的推理,我是否也可以断言在 Spring 中我不能有一个带有 @Bean 注释的 final 方法?
因为,如前面的示例所示,我在启动时创建了我的配置类的子类(代理),对于每个 bean,都会在子类中缓存一个实例 如果它是最终的,那是不可能的(但我绝对不确定这个断言)
我错过了什么吗?能给我具体的解释吗?
Tnx
最佳答案
Spring 为使用 @Configuration
类注解的类创建动态代理。 Spring 使用 CGLIB 来扩展你的类来创建代理。因此,配置类不能是最终的。
关于 accountRepository()
被调用两次:
如果你调用 accountRepository()
方法来创建一个实例,它就不再是一个 Spring 托管的 bean。 Spring 不会知道以这种方式创建的实例。因此,您最终会得到 JdbcAccountRepository
如果您进行如下配置,您可以保留单例行为:
@Bean
public TransferService transferService(JdbcAccountRepository jdbcAcctRepo) {
TransferServiceImpl service = new TransferServiceImpl();
service.setAccountRepository(jdbcAcctRepo);
return service;
}
@Bean
public AccountService accountService(JdbcAccountRepository jdbcAcctRepo) {
return new AccountServiceImpl(jdbcAcctRepo);
}
关于java - 为什么在 Spring 中我不允许使用 @Configuration 注释最终类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29074270/