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.