当前位置: 首页 > 知识库问答 >
问题:

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

秦才
2023-03-14

我正在学习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());
}

乍一看,这种情况可能看起来很奇怪,因为第一个方法(帐户存储库())将JdbcAcCountRepository对象实例化为一个bean,该对象具有id=AcCountRepository,遵循Spring默认行为,是一个单例

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

因此,为了解决这种情况,Spring使用基于继承的代理策略,希望创建我的配置类(由@configuration注释的配置类)的子类,它是这样做的:

>

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

    子类仅在第一次实例化时调用super

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

    公共类AppConfig$$enhancerbyglib$扩展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注释来注释最终的方法吗?

    因为,如上例所示,当启动时创建配置类的子类(代理)时,对于每个bean,一个实例被缓存在子类中,如果它是最终的,则不可能(但我绝对不确定这个断言)

    我是不是漏了什么?你能给我确切的解释吗?

    tnx

  • 共有1个答案

    滕夜洛
    2023-03-14

    Spring为带有@Configuration类注释的类创建动态代理。Spring使用CGLIB扩展类以创建代理。因此,配置类不能是最终的。

    关于被调用两次的帐户库()

    如果调用accountRepository()方法来创建实例,那么它就不再是Spring管理的bean。Spring对以这种方式创建的实例一无所知。因此,您将得到多个jdbccountrepository

    如果按以下方式配置,则可以保留单例行为:

    @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 8最有用的功能之一是接口上的新方法。引入它们的原因基本上有两个(可能还有其他原因): 提供实际的默认实现。例: 允许JDK API演进。例: 从API设计人员的角度来看,我希望能够在接口方法上使用其他修饰符,例如。在添加便捷方法时,这将很有用,以防止在实现类时“意外”覆盖: 如果已经上过课,以上是已经很普遍的做法: 现在,并且显然是相互矛盾的关键字,但是默认关键字本身并没有严

    • 谁能告诉我在java中使main方法成为final的用途。

    • 我正在学习Spring框架,但我不能理解注释的确切含义以及应该对哪些类进行注释。在Spring Boot文档中,说应用程序类应该是class。 Spring Boot支持基于Java的配置。虽然可以使用XML源调用SpringApplication.run(),但我们通常建议您的主要源是@Configuration类。 在尝试了解时,我发现用注释类表明Spring IoC容器可以使用该类作为bea

    • 问题内容: 为什么在最终课程中允许受保护的成员? 这不应该是编译时错误吗? 编辑:正如人们指出的那样,您可以使用默认修饰符来获得相同的程序包访问权限。它的行为应该完全相同,因为protected是默认+子类,而final修饰符明确地拒绝了子类,因此我认为答案不只是提供相同的程序包访问。 问题答案: 该改性剂是必要的方法其覆盖从基类的方法,在没有那些构件暴露于所述。 通常,您可以引入很多不必要的规则

    • 我遇到了下面的Java代码,起初看起来不错,但从未编译过: 下面是IDE :变量USER_ID可能已分配的错误消息。 将值赋值给静态最终变量有问题吗?

    • 我有一个配置文件,我想根据配置文件在其中创建不同的bean。 出于某种原因,这是可行的: 这不是,在Eclipse中给出错误消息: 此位置不允许注释 我宁愿使用第二个,但我不确定我是否可以。Spring API说它应该可以工作: 可通过以下任一方式使用配置文件注释: 作为任何类上的类型级注释,直接或间接使用组件进行注释,包括配置类 作为元注释,用于编写自定义原型注释 作为任何@Bean方法上的方法