Spring boot 2.1 bean override vs. Primary

后端 未结 4 842
名媛妹妹
名媛妹妹 2020-12-28 14:04

With Spring Boot 2.1 bean overriding is disabled by default, which is a good thing.

However I do have some tests where I replace beans with mocked instances using Mo

相关标签:
4条回答
  • 2020-12-28 14:20

    Overriding beans means that there may be only one bean with a unique name or id in the context. So you can provide two beans in the following way:

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

    If you add @Primary then primary bean will be injected by default in:

    @Autowired
    BService bService;
    
    0 讨论(0)
  • 2020-12-28 14:21

    spring.main.allow-bean-definition-overriding=true can be placed in test configurations. If you need extensive integration testing, you will need to override beans at some point. It's inevitable.

    Though the correct answer has already been provided, it implies that your bean will have different names. So, technically, it's not an override.

    If you need a real override (because you use @Qualifiers, @Resources or something similar), since Spring Boot 2.X is only possible using the spring.main.allow-bean-definition-overriding=true property.

    Update: Be careful with Kotlin Bean Definition DSL. In Spring Boot it will require a custom ApplicationContextInitializer, like so:

    class BeansInitializer : ApplicationContextInitializer<GenericApplicationContext> {
    
        override fun initialize(context: GenericApplicationContext) =
                beans.initialize(context)
    
    }
    

    Now if you decide to override one of such DSL-based beans in your test via @Primary @Bean method, it will not do. The initializer will kick in after @Bean methods and you'd still get the initial, DSL-based bean in your tests even with @Primary on the test @Bean. One other option would be to also create a test initializer for your tests and list them all in your test properties, like so(order matters):

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

    Bean Definition DSL also supports primary property via:

    bean(isPrimary=true) {...}
    

    - which you'll need to eliminate ambiguity when you try to inject a bean, however main:allow-bean-definition-overriding: true is not needed if you go pure DSL way.

    (Spring Boot 2.1.3)

    0 讨论(0)
  • 2020-12-28 14:23

    I make the testing beans available only in test profile, and allow overriding for just while testing, like this:

    @ActiveProfiles("test")
    @SpringBootTest(properties = {"spring.main.allow-bean-definition-overriding=true"})
    class FooBarApplicationTests {
    
      @Test
      void contextLoads() {}
    }
    
    

    The bean I am mocking in the test configuration:

    @Profile("test")
    @Configuration
    public class FooBarApplicationTestConfiguration {
      @Bean
      @Primary
      public SomeBean someBean() {
        return Mockito.mock(SomeBean.class);
      }
    }
    
    
    0 讨论(0)
  • 2020-12-28 14:33

    It is allowed to override @Component with @Bean by default. In your case

    @Service
    public class AService {
    }
    
    @Component
    public class BService {
        @Autowired
        public BService() { ... }
    }
    
    @Configuration
    @ComponentScan
    public BaseConfiguration {
    }
    
    @Configuration
    // WARNING! Doesn't work with @SpringBootTest annotation
    @Import({BaseConfiguration.class})
    public class TestConfiguration {
        @Bean // you allowed to override @Component with @Bean.
        public BService bService() {
            return Mockito.mock(BService.class);
        }
    }
    
    0 讨论(0)
提交回复
热议问题