Correctness16 - SpotBugsExtensionForSpringFrameWork/CS5098 GitHub Wiki

(Suitable) Bug Name

Description

Spring beans are identified by their names within an ApplicationContext. Thus, bean overriding is a default behavior that happens when we define a bean within an ApplicationContext which has the same name as another bean.

@Configuration
public class TestConfiguration1 {
    class TestBean1 {
        private String name;

        // standard getters and setters
    }

    @Bean
    public TestBean1 testBean(){ // same bean name
        return new TestBean1();
    }
}

------------------------------------------------------------
@Configuration
public class TestConfiguration2 {
    class TestBean2 {
        private String name;

        // standard getters and setters
    }

    @Bean
    public TestBean2 testBean(){ // same bean name
        return new TestBean2();
    }
}
------------------------------------------------------------
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {TestConfiguration1.class, TestConfiguration2.class})
public class SpringBootBeanDefinitionOverrideExceptionIntegrationTest {
    @Test
    public void whenBeanOverridingAllowed_thenTestBean2OverridesTestBean1() {
        Object testBean = applicationContext.getBean("testBean"); // Multiple testBean!!
        assertThat(testBean.getClass()).isEqualTo(TestConfiguration2.TestBean2.class);
				// BeanDefinitionOverrideException error occur    
    }
}

Solutions

// Solution 1
@Bean
public TestBean1 testBean1() { // not duplicate name
    return new TestBean1(); 
}

@Bean
public TestBean2 testBean2() { // not duplicate name
    return new TestBean2();
}
------------------------------------------------------------
// Solution 2
@Bean("testBean1") // like this
public TestBean1 testBean() {
    return new TestBean1();
}

@Bean("testBean2") // like this
public TestBean1 testBean() {
    return new TestBean2();
}
------------------------------------------------------------
// Solution 3
@Component("testBean1") // class level definition
class TestBean1 {

    private String name;

    // standard getters and setters

}

@Component("testBean2") // class level definition
class TestBean2 {

    private String name;

    // standard getters and setters

}
------------------------------------------------------------
// if the 3rd party library has same bean name,
// Solution 4
spring.main.allow-bean-definition-overriding=true
// but allowing bean overriding can produce unexpected behavior unless we know the dependency hierarchy of our beans well enough.

Reference List

baeldung