弹簧靴 2.1 豆覆盖与主

2022-09-01 02:41:04

使用Spring Boot 2.1,默认情况下禁用了bean覆盖,这是一件好事。

但是,我确实有一些测试,其中我使用Mockito用模拟实例替换bean。使用默认设置,具有此类配置的测试将由于 Bean 覆盖而失败。

我发现唯一可行的方法是通过应用程序属性启用Bean覆盖:

spring.main.allow-bean-definition-overriding=true

但是,我真的想确保为我的测试配置设置最少的bean定义,这将在禁用覆盖的情况下由spring指出。

我覆盖的豆子是

  • 在导入到我的测试配置中的另一个配置中定义
  • 通过注释扫描自动发现豆子

我所想的应该在测试配置中工作,覆盖bean并在其上打一个,就像我们习惯于数据源配置一样。然而,这没有任何效果,让我想知道:和残疾豆子是否矛盾?@Primary@Primary

一些例子:

package com.stackoverflow.foo;
@Service
public class AService {
}

package com.stackoverflow.foo;
public class BService {
}

package com.stackoverflow.foo;
@Configuration
public BaseConfiguration {
    @Bean
    @Lazy
    public BService bService() {
        return new BService();
    }
}

package com.stackoverflow.bar;
@Configuration
@Import({BaseConfiguration.class})
public class TestConfiguration {
    @Bean
    public BService bService() {
        return Mockito.mock(BService.class);
    }
}

答案 1

spring.main.allow-bean-definition-overriding=true可以放置在测试配置中。如果您需要广泛的集成测试,则需要在某个时候覆盖Bean。这是不可避免的。

虽然已经提供了正确的答案,但它意味着你的豆子将有不同的名称。因此,从技术上讲,它不是一个覆盖。

如果你需要一个真正的覆盖(因为你使用,或类似的东西),因为Spring Boot 2.X只能使用该属性。@Qualifiers@Resourcesspring.main.allow-bean-definition-overriding=true

更新:小心 Kotlin Bean Definition DSL。在Spring Boot中,它将需要一个自定义的AppplicationContextInitializer,如下所示:

class BeansInitializer : ApplicationContextInitializer<GenericApplicationContext> {

    override fun initialize(context: GenericApplicationContext) =
            beans.initialize(context)

}

现在,如果您决定通过方法在测试中覆盖其中一个基于DSL的bean,它将不起作用。初始值设定项将在方法之后启动,即使在测试中,您仍然可以在测试中获得基于DSL的初始bean。另一种选择是为测试创建一个测试初始值设定项,并在测试属性中列出它们,如下所示(顺序很重要):@Primary @Bean@Bean@Primary@Bean

context:
    initializer:
        classes: com.yuranos.BeansInitializer, com.yuranos.TestBeansInitializer

Bean Definition DSL 还通过以下方式支持主属性:

bean(isPrimary=true) {...}

- 当你尝试注入一个bean时,你需要消除歧义,但是main:allow-bean-definition-overovering:如果你采用纯DSL的方式,则不需要true。

(弹簧靴 2.1.3)


答案 2

覆盖 Bean 意味着上下文中可能只有一个具有唯一名称或 ID 的 Bean。因此,您可以通过以下方式提供两个豆子:

package com.stackoverflow.foo;
@Configuration
public class BaseConfiguration {
   @Bean
   @Lazy
   public BService bService1() {
       return new BService();
   }
}

package com.stackoverflow.bar;
@Configuration
@Import({BaseConfiguration.class})
public class TestConfiguration {
    @Bean
    public BService bService2() {
        return Mockito.mock(BService.class);
    }
}

如果添加,则默认情况下将注入主 bean:@Primary

@Autowired
BService bService;

推荐