spring-projects / spring-framework

Spring Framework
https://spring.io/projects/spring-framework
Apache License 2.0
56.72k stars 38.15k forks source link

Regression in duplicate beans with `@Primary` in 6.2.0 #33920

Open iparadiso opened 2 days ago

iparadiso commented 2 days ago

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

philwebb commented 2 days ago

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.