为什么在Spring中我不允许用@Configuration注释最终的类?

时间:2015-03-16 10:15:05

标签: java spring spring-mvc annotations spring-annotations

我正在攻读Spring Core认证,我对基于学习材料的这个问题的答案有些怀疑。

  

为什么不允许使用@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 ,遵循Spring默认行为,是 singleton

第二种和第三种方法调用两次以上 accountRepository()方法,该方法应该再实例化两次 JdbcAccountRepository 对象,这不是可能因为它是单身人士!!!

因此,为了解决这种情况,Spring使用基于继承的代理策略,该策略期望创建我的配置类的子类(由注释的那个@Configuration )确实如此:

  • 对于每个bean,实例都缓存在子类中

  • 子类仅在首次实例化时调用super

因此子类是入口点,因为此子类实现了以下行为:

public class AppConfig $$ EnhancerByCGLIB $ extends 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 中,最终的类不能被子类化

这是对的吗?

使用相同的推理我还可以断言在Spring 我不能用@Bean注释注释最终方法吗?

因为,如前面的例子所示,我知道在创建启动时,我的配置类的子类(代理)发生了对于每个bean,一个实例缓存在子类< / strong>如果它是最终的,那是不可能的(但我绝对不确定这个断言)

我错过了什么吗?你能给我一个确切的解释吗?

TNX

1 个答案:

答案 0 :(得分:8)

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);
}