spring Bean Overriding 2.1.x in nested class @Configuration @Bean creation fails with 'A bean with that name has already been defined'

Dirk Hoffmann :

upgrading to spring-boot 2.1.0.M4 Bean overriding has been disabled by default. If you are relying on overriding, you will need to set spring.main.allow-bean-definition-overriding to true.

But why is a Bean defined in an inner class also treated like a duplicate bean definition. Is this a bug? or has this some explanation?

e.g.:

@Configuration
public class BusinessLogicConfig {

    @Configuration
    class BusinessLogicSourceConfig {
        @Bean
        public BusinessLogic businessLogic() {
            return new BusinessLogic("source");
        }
    }
}

works fine up to spring-boot 2.0.x

but when using e.g. spring-boot 2.1.0.M4 it gives me an error on startup:

The bean 'businessLogic', defined in class path resource [com/example/di/bootconfigs/BusinessLogicConfig$BusinessLogicTier1Config.class], could not be registered.
A bean with that name has already been defined in URL [jar:file:/.../di/build/libs/di-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/example/di/businesslogic/BusinessLogic.class]
and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

As I clearly only have a single definition of the bean (only defined in an inner @Configuration class) this seems like a bug to me.

If you ask why I am using a nested inner @Configuration class:

I often have demo code, demonstrating distributed system behavior in which I need more than one app to demonstrate things. As I don't want to have multiple App code, I just start the same App with different profiles and the profile is injecting "different business logic" which I want to "keep together" in one file, like:

@Configuration
public class BusinessLogicConfig {

    @Value("${app.info.instance_index}")
    private String instanceIndex;

    @Profile({ "source" }) // unused fake BusinessLogic for pure sources
    @Configuration
    class BusinessLogicSourceConfig {
        @Bean
        public BusinessLogic businessLogic() {
            return new BusinessLogic("source", instanceIndex);
        }
    }

    @Profile({ "sink" }) // unused fake BusinessLogic for pure sinks
    @Configuration
    class BusinessLogicSinkConfig {
        @Bean
        public BusinessLogic businessLogic() {
            return new BusinessLogic("sink", instanceIndex);
        }
    }

    @Profile({ "tier1" })
    @Configuration
    class BusinessLogicTier1Config {
        @Bean
        public BusinessLogic businessLogic() {
            return new BusinessLogic("tier1", instanceIndex);
        }
    }

    @Profile({ "tier2" })
    @Configuration
    class BusinessLogicTier2Config {
        @Bean
        public BusinessLogic businessLogic() {
            return new BusinessLogic("tier2", instanceIndex);
        }
    }

    @Profile({ "tier3" })
    @Configuration
    class BusinessLogicTier3Config {
        @Bean
        public BusinessLogic businessLogic() {
            return new BusinessLogic("tier3", instanceIndex);
        }
    }

}
Dirk Hoffmann :

Turns out its not the @Configuration class nesting. It is the BusinessLogic class itself, that is a Bean with name BusinessLogic as it is a @Component. so above creates a second version of a Bean named BusinessLogic.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=109902&siteId=1