Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
612 views
in Technique[技术] by (71.8m points)

java - Spring boot 2.1 bean override vs. Primary

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 Mockito. With the default setting Tests with such a configuration will fail due to bean overriding.

The only way I found worked, was to enable bean overriding through application properties:

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

However I would really like to ensure minimal bean definition setup for my test configuration, which would be pointed out by spring with the overriding disabled.

The beans that I am overriding are either

  • Defined in another configuration that imported into my test configuration
  • Auto-discovered bean by annotation scanning

What I was thinking should work in the test configuration overriding the bean and slap a @Primary on it, as we are used to for data source configurations. This however has no effect and got me wondering: Is the @Primary and the disabled bean overriding contradictory?

Some example:

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);
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...