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

标签 java spring spring-mvc annotations spring-annotations

我正在学习 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 遵循 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/

相关文章:

java - net.serenitybdd.core.exceptions.SerenityManagedException : SERENITY_DISABLE_REST_CALLS_AFTER_FAILURES

java - 这两种方式创建对象有什么区别

java - 使用 Java 库的官方 JSON 验证 JSON

java - @Query 由 : org. hibernate.hql.internal.ast.QuerySyntaxException 引起:主题未映射错误

java - spring web-mvc 4 java 配置不起作用

java - jquery ajax GET 上的 HTTP 状态 404(未找到)到 Spring Controller ?

java - 如何显示列表中的最小值和最大值?

java - 在对 Spring Boot REST API 的多次调用中使用相同的 JDBC 连接

java - 捕获异常的 Spring 事务

spring - 在 Spring 3 中为 url 映射 jsp 而不使用 Controller