Dirk Hoffmann opened SPR-17365 and commented
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$BusinessLogicSourceConfig.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);
}
}
}
source code at: git@gitlab.com:hoffi_scratch/di.git
Affects: 5.1 GA
Reference URL: https://gitlab.com/hoffi_scratch/di
Comment From: spring-projects-issues
Andy Wilkinson commented
You do have defined two beans named businessLogic
. You have a @Bean
method called businessLogic
. The method name is used as the bean's name so the bean's name is businessLogic
. Your BusinessLogic
class is annotated with @Component
and is being picked up by component scanning. The default bean name for a class named BusinessLogic
is businessLogic
so you end up with two beans with the same name, hence the attempted override.