Observed Issue
In Spring Boot 3.3, duplicate named beans can be defined where @Primary
can be used as the default. In Spring Boot 3.4 RC1, this behavior is no longer the same.
Consider the following example of two named beans with different behavior.
@TestConfiguration
public class TestConfig {
@Bean(name = "foo")
@Primary
@ConditionalOnProperty(name = "foo.truthy", havingValue = "true", matchIfMissing = true)
Boolean fooIsTrue() {
return true;
}
@Bean(name = "foo", defaultCandidate = false)
Boolean fooIsFalse() {
return false;
}
}
When validated in the following test, SB 3.3 expectedly injects the "truthful" bean version marked as @Primary
.
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = { TestConfig.class })
public class ConditionalTest {
@Autowired
@Qualifier("foo")
Boolean foo;
@Test
void checkFoo() {
assertTrue(foo);
}
}
When this same test is applied in Spring Boot 3.4 RC1, the @Primary
"foo" bean is no longer created, causing this test evaluation to fail.
Is this an exepected change in behavior?
Reproducer
This test is available here
Comment From: philwebb
I think https://github.com/spring-projects/spring-framework/commit/552936627a4242a839ab00156970134ec933eef9 is the commit that changed things. Issue #33330
Add a breakpoint in ConfigurationClassBeanDefinitionReader.isOverriddenByExistingDefinition
. In the previous version we return true
here on the second call. In the newer version, we return false
.
It's interesting that we don't get a hard failure.
Comment From: jhoeller
I've revised the ConfigurationClassBeanDefinitionReader.isOverriddenByExistingDefinition
algorithm to explicitly raise a BeanDefinitionOverrideException
in case of an unexpected override when allowBeanDefinitionOverriding=false
, leading to a consistent failure - while preserving the original override behavior in case of allowBeanDefinitionOverriding=true
. This should keep #33300 happy while also addressing this regression here, restoring compatibility with Framework 6.1.x. The reproducer seems to pass so far.
Note that bean definition overriding needs to be explicitly allowed for such an arrangement to be accepted on 6.2. This may have to be activated explicitly for production setups since we generally prefer to keep it disallowed, and the definition of what constitutes an override is somewhat broader in 6.2 now.