1、在同一个xml中配置了相同的bean的id。EX:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "/spring-beans.dtd">
<beans>
<bean id="test" class="com.xxx.Bean">
<property name="name" value="111" />
</bean>
</beans> <beans>
<bean id="test" class="com.xxx.Bean">
<property name="name" value="222" />
</bean>
</beans>
复制代码
这种情况下,会直接抛出异常"Cannot register bean definition [xxx] for bean xxx: There is already [xxx] bound."
2、在不同的xml中配置相同的bean的id。EX:
test1.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "/spring-beans.dtd">
<beans>
<bean id="test" class="com.xxx.Bean">
<property name="name" value="111" />
</bean>
</beans>
复制代码
test2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "/spring-beans.dtd">
<beans>
<bean id="test" class="com.xxx.Bean">
<property name="name" value="222" />
</bean>
</beans>
复制代码
这种情况下text2.xml中的bean会直接覆盖text1.xml中的bean,Spring最终只会把text2.xml中的bean加载到IOC容器中。
此时spring并不会报错,只会打印info级别的日志信息,"Overriding bean definition for bean xxx with a different definition: replacing [xxx] with [xxx]" 这种情况下,要排查问题很困难。
通过查看spring源码,我们发现在springIOC容器初始化时,有一个关键变量allowBeanDefinitionOverriding。
再来看下源码:
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
BeanDefinition oldBeanDefinition;
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {------------------6
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
this.beanDefinitionMap.put(beanName, beanDefinition);
复制代码
可以看到在第6行,通过判断allowBeanDefinitionOverriding变量的值,来决定是覆盖还是抛出异常,而allowBeanDefinitionOverriding这个值默认是true。所以默认情况下是直接覆盖的,不会抛出异常。
那么我们很容易就想到,把allowBeanDefinitionOverriding的值改为false就可以解决问题。
查看源码,我们发现DefaultListableBeanFactory类提供了赋值allowBeanDefinitionOverriding变量的方法:
public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;
复制代码
所以我们只要调用这个方法,把allowBeanDefinitionOverriding赋值成false就成功了。
那么如何修改呢? 我们来看下都有哪些类调用了setAllowBeanDefinitionOverriding()方法:
可以看到,在AbstractRefreshableApplicationContext类中调用了该方法, 我们继续跟进这个类中看:
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
复制代码
发现是在customizeBeanFactory()方法中调用的,接着我们来跟踪this.allowBeanDefinitionOverriding变量,看看是在哪里设置的:
* Set whether it should be allowed to override bean definitions by registering
* a different definition with the same name, automatically replacing the former.
* If not, an exception will be thrown. Default is "true".
*
@see
org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
public
void
setAllowBeanDefinitionOverriding
(
boolean
allowBeanDefinitionOverriding
) {
this
.
allowBeanDefinitionOverriding
= allowBeanDefinitionOverriding;
复制代码
可以看到AbstractRefreshableApplicationContext暴露了setAllowBeanDefinitionOverriding()方法来设置allowBeanDefinitionOverriding变量的值。 直接在AbstractRefreshableApplicationContext这个类中查看哪里调用了这个方法,发现找不到, 那我们就看看他有哪些子类。
我们会发现一个非常熟悉的类:ClassPathXmlApplicationContext 接下来就简单了,我们只要通过ClassPathXmlApplicationContext类调用父类的setAllowBeanDefinitionOverriding()方法,就可以设置allowBeanDefinitionOverriding变量的值了。
代码如下:
public static void main(String[] args){
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext(new String[]{"context.xml", "context1.xml"}, false);
applicationContext.setAllowBeanDefinitionOverriding(false);
applicationContext.refresh();
Student student = (Student)applicationContext.getBean("student");
System.out.println(student.toString());
复制代码
大功告成~