转载至:http://blog.csdn.net/linuxerlin/article/details/38778761

问题:

最近在做公共框架的构建,由于采用了模块化的插件机制,在开发的过程中,发现不同开发人员的spring配置中,出现了两个bean的配置id和实现类名称都一样的情况。
例如有下面的bean类:
package com.XXX.common.test;
public class SameNameBean {
       private String beanName ;
       public void setBeanName(String beanName) {
             this.beanName = beanName;
      }
       public String test() {
             return "Hello " + beanName;
      }
}
和两个xml的配置:
beanContext1.xml:
<?xml version="1.0" encoding= "UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "/spring-beans.dtd">
<beans>
     <bean id="testNameBean" class="com.xxx.common.test.SameNameBean" >
          <property name="beanName" value="beanContext1" />
     </bean >
</beans>
beanContext2.xml:

<?xml version="1.0" encoding= "UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "/spring-beans.dtd">
<beans>
     <bean id="testNameBean" class="com.xxx.common.test.SameNameBean" >
          <property name="beanName" value="beanContext2" />
     </bean >
</beans>
当spring容器初始化时候同时加载这两份配置文件到当前的上下文的时候,代码如下:
public class TestBean {
       public static void main(String[] args) {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                         new String[] { "classpath*:beanContext*.xml" });
             //context.setAllowBeanDefinitionOverriding(false);
             //context.refresh();
            SameNameBean sameNameBean = (SameNameBean) context
                        .getBean( "testNameBean");
            System. out.println(sameNameBean.test());
      }
}

执行结果是:

Hello beanContext2

从结果可以看出,beanContext2.xml的bean的配置覆盖了beanContext1.xml中bean的配置,而且在spring初始化上下文的过程中没有任何的警告。这样如果在项目中定义了两个id同名的bean,并且他们的实现方式类又是不一样的,在项目的业务逻辑看起来就会非常诡异,而且,如果也不利于排除问题。

解决问题:

那么,我们如何来解决这个问题吗?靠程序员自律?绝对不定义重复名称的bean?我觉得这个是不靠谱的,只有通过在程序中引入一种交错机制才能解决这个问题。

首先,我们将上面那段程序的log4j日志打开,看看在spring在初始化的时候面对有两个同名的bean是怎么处理的。

- INFO - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@aa9835: display name [org.springframework.context.support.ClassPathXmlApplicationContext@aa9835]; startup date [Sat Jun 19 18:23:30 CST 2014]; root of context hierarchy
- INFO - Loading XML bean definitions from class path resource [beanContext1.xml]
- DEBUG - Using JAXP provider [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl]
- DEBUG - Found beans DTD [file:///spring-beans.dtd] in classpath: spring-beans.dtd
- DEBUG - Loading bean definitions
- DEBUG - Loaded 1 bean definitions from location pattern [beanContext1.xml]
- INFO - Loading XML bean definitions from class path resource [beanContext2.xml]
- DEBUG - Using JAXP provider [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl]
- DEBUG - Found beans DTD [file:///spring-beans.dtd] in classpath: spring-beans.dtd
- DEBUG - Loading bean definitions
- INFO - Overriding bean definition for bean 'testNameBean': replacing [Generic bean: class [com.xxx.common.test.SameNameBean]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [beanContext1.xml]] with [Generic bean: class [com.xxx.common.test.SameNameBean]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [beanContext2.xml]]

- DEBUG - Loaded 0 bean definitions from location pattern [beanContext2.xml]
- INFO - Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@aa9835]:org.springframework.beans.factory.support.DefaultListableBeanFactory@1662dc8
- DEBUG - 1 beans defined in org.springframework.context.support.ClassPathXmlApplicationContext@aa9835: display name [org.springframework.context.support.ClassPathXmlApplicationContext@aa9835]; startup date [Sat Jun 19 18:23:30 CST 2014]; root of context hierarchy
- DEBUG - Unable to locate MessageSource with name 'messageSource': using default [org.springframework.context.support.DelegatingMessageSource@1cb25f1]
- DEBUG - Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [org.springframework.context.event.SimpleApplicationEventMulticaster@503429]
- INFO - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1662dc8: defining beans [testNameBean]; root of factory hierarchy

- DEBUG - Creating shared instance of singleton bean 'testNameBean'

- DEBUG - Creating instance of bean 'testNameBean'

- DEBUG - Eagerly caching bean 'testNameBean' to allow for resolving potential circular references

- DEBUG - Finished creating instance of bean 'testNameBean'

- DEBUG - Returning cached instance of singleton bean 'testNameBean'

以上日志中标红的是关键,spring在处理有重名的bean的定义的时候原来是使用的覆盖(override)的方式。我们来看看它是如何覆盖的。

在org.springframework.beans.factory.support.DefaultListableBeanFactory这个类中有这样一段代码:
    synchronized (this.beanDefinitionMap) {
               Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
               if (oldBeanDefinition != null) {
                    if (!this.allowBeanDefinitionOverriding) {
                         throw new BeanDefinitionStoreException(beanDefinition
                                   .getResourceDescription(), beanName,
                                   "Cannot register bean definition ["
                                             + beanDefinition + "] for bean '"
                                             + beanName + "': There is already ["
                                             + oldBeanDefinition + "] bound.");
                    } else {
                         if (this.logger.isInfoEnabled()) {
                              this.logger
                                        .info("Overriding bean definition for bean '"
                                                  + beanName + "': replacing ["
                                                  + oldBeanDefinition + "] with ["
                                                  + beanDefinition + "]");
                         }
                    }
               } else {
                    this.beanDefinitionNames.add(beanName);
                    this.frozenBeanDefinitionNames = null;
               }
               this.beanDefinitionMap.put(beanName, beanDefinition);
               resetBeanDefinition(beanName);
          }
spring ioc容器在加载bean的过程中会去判断beanName 是否有重复,如果发现重复的话再根据allowBeanDefinitionOverriding 这个成员变量,如果是false的话则抛出BeanDefinitionStoreException 这个异常,如果为true的话就会覆盖这个bean的定义。

所以,解决这个问题的办法就比较简单了,只要将这个allowBeanDefinitionOverriding值在spring初始化的时候设置为false就行了。

在web工程中加载spring容器,一般都会通过加载下面的listener:
<listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

在这个listener中会构造 org.springframework.web.context.ContextLoader 这个构造器来加载bean。所以,只要扩展 ContextLoader 和ContextLoaderListener这两个类就行了,代码如下:

CustomSpringContextLoader:

package com.xxx.itpub.contrl.context;
import javax.servlet.ServletContext;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.support.XmlWebApplicationContext;
public class CustomSpringContextLoader  extends ContextLoader {
    @Override
    protected void customizeContext(ServletContext servletContext,
            ConfigurableWebApplicationContext applicationContext) {
        XmlWebApplicationContext context = (XmlWebApplicationContext) applicationContext;
        context.setAllowBeanDefinitionOverriding( false);
    }
}
CustomSpringContextLoaderListener :
package com.xxx.itpub.contrl.listener;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.ContextLoaderListener;
import com.eshore.itpub.contrl.context.CustomSpringContextLoader;
public class CustomSpringContextLoaderListener extends ContextLoaderListener {
    @Override
    protected ContextLoader createContextLoader() {
        return new CustomSpringContextLoader();
    }
}
最后修改WEB-INF下web.xml 文件,修改listener的配置,如下:
<listener>
   <listener-class> com.xxx.itpub.contrl.listener.CustomSpringContextLoaderListener </listener-class>
</listener>
设置完就ok了,这样被加载的xml文件中如果再出现名字相同的bean,spring在加载过程中就会抛出下面的异常:
[2014-08-07 19:32:04.329]-[ERROR] org.springframework.web.context.ContextLoader Context initialization failed
org.springframework.beans.factory.parsing.BeanDefinitionParsingException : Configuration problem: Failed to register bean definition with name 'publicDAO'
Offending resource: file [D:\software\dev\apache-tomcat-6.0.16\webapps\itpub_web\WEB-INF\classes\conf\spring\dbContext.xml]; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException : Invalid bean definition with name 'publicDAO' defined in file [D:\software\dev\apache-tomcat-6.0.16\webapps\itpub_web\WEB-INF\classes\conf\spring\dbContext.xml]: Cannot register bean definition [Generic bean: class [com.xxx.itpub.daopub.database.impl.PublicDAOImpl]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [D:\software\dev\apache-tomcat-6.0.16\webapps\itpub_web\WEB-INF\classes\conf\spring\dbContext.xml]] for bean 'publicDAO': There is already [Generic bean: class [com.xxx.itpub.daopub.database.impl.PublicDAOImpl]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [D:\software\dev\apache-tomcat-6.0.16\webapps\itpub_web\WEB-INF\classes\conf\spring\beansContext.xml]] bound.
      at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
      at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
      at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:76)
      at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processBeanDefinition(DefaultBeanDefinitionDocumentReader.java:320)
      at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement(DefaultBeanDefinitionDocumentReader.java:203)
      at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:182)
      at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:139)
      at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:108)
      at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493)
      at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390)
      at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)
      at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)
      at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174)
      at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209)
      at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180)
      at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125)
      at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94)
      at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130)
      at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:537)
      at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:451)
      at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
      at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
      at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
      at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3843)
      at org.apache.catalina.core.StandardContext.start(StandardContext.java:4350)
      at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
      at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
      at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
      at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:924)
      at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:887)
      at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492)
      at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1147)
      at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
      at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
      at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
      at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
      at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
      at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
      at org.apache.catalina.core.StandardService.start(StandardService.java:516)
      at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
      at org.apache.catalina.startup.Catalina.start( Catalina.java:578)
      at sun.reflect.NativeMethodAccessorImpl.invoke0( Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
      at java.lang.reflect.Method.invoke(Unknown Source)
      at org.apache.catalina.startup.Bootstrap.start( Bootstrap.java:288)
      at org.apache.catalina.startup.Bootstrap.main( Bootstrap.java:413)
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException : Invalid bean definition with name 'publicDAO' defined in file [D:\software\dev\apache-tomcat-6.0.16\webapps\itpub_web\WEB-INF\classes\conf\spring\dbContext.xml]: Cannot register bean definition [Generic bean: class [com.eshore.itpub.daopub.database.impl.PublicDAOImpl]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [D:\software\dev\apache-tomcat-6.0.16\webapps\itpub_web\WEB-INF\classes\conf\spring\dbContext.xml]] for bean 'publicDAO': There is already [Generic bean: class [com.xxx.itpub.daopub.database.impl.PublicDAOImpl]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [D:\software\dev\apache-tomcat-6.0.16\webapps\itpub_web\WEB-INF\classes\conf\spring\beansContext.xml]] bound.
      at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(DefaultListableBeanFactory.java:657)
      at org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerBeanDefinition(BeanDefinitionReaderUtils.java:148)
      at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processBeanDefinition(DefaultBeanDefinitionDocumentReader.java:317)
      ... 43 more
2014-8-7 19:32:04 org.apache.catalina.core.StandardContext listenerStart
严重: Exception sending context initialized event to listener instance of class com.eshore.itpub.contrl.listener.CustomSpringContextLoaderListener
org.springframework.beans.factory.parsing.BeanDefinitionParsingException : Configuration problem: Failed to register bean definition with name 'publicDAO'
此时根据异常信息,去除掉同名的id之后,就可以了。
对于自动识别Autowired的同样有效。

Spring beanid 同名覆盖问题解决相关推荐

  1. Struts2 + Hibernate + Spring 以及javaweb模块问题解决(1)

    Struts2 + Hibernate + Spring 以及javaweb模块问题解决 1.资源文件的配置:src文件夹里面要配置,action所在的目录中也要配置. 2.<s: action ...

  2. C++小练习-求长方体表面积(同名覆盖)

    一.问题描述 描述 现在有长方形类(rectangle),请以此为基类构建长方体类(cuboid)并实现求表面积的area方法. 输入描述: 输入三个整数x,y,zx,y,z分别表示长宽高. 输出描述 ...

  3. C++继承中父类和子类之间的同名覆盖

    文章目录 1 C++继承中父类和子类的同名成员变量 1.1 父类和子类的同名成员变量 2 C++继承中父类和子类的同名成员函数 2.1 父类和子类中的同名成员函数 1 C++继承中父类和子类的同名成员 ...

  4. spring拦截器覆盖_Spring中使用Interceptor拦截器

    SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理.比如通过它来进行权限验证,或者是来判断用户是否登陆,或者是像12306 那 ...

  5. springboot导入后Spring包飘红问题解决

    问题现象:导入到idea->File->new->Project from existing source的Springboot项目在依赖下载完毕后,很多spring等导包问题都出现 ...

  6. 算法设计与分析--棋盘覆盖问题解决思想

    问题:在一个2^k * 2^k个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格,则称该棋盘为一特殊棋盘.该棋盘为特殊棋盘,蓝色的方格为特殊方格.要用图2中的4种不同形态的L型骨牌覆 ...

  7. Spring Security跨域问题解决

    前文介绍了:Spring 处理跨域问题的三种方案 现在来看看 Spring Security 的跨域问题解决方案,共有三种方案.(摘自<深入浅出Spring Security>) 在实际项 ...

  8. java对象相互覆盖问题解决

    业务需求场景:     明细内容数据表:当前例子中最小粒度的表.     明细内容数据分组表(即将多个明细数据以包的形式组合起来形成一个组合包):与明细内容数据多对多的关系.     主数据表(主数据 ...

  9. H5导航栏被IOS系统状态栏覆盖问题解决

    问题描述 在开发h5小程序时发现安卓系统中页面正常显示,但在iPhone中导航栏被系统状态栏覆盖. 解决方法 env()和constant(),是IOS11新增特性,Webkit的css函数,用于设定 ...

最新文章

  1. 3.1 Tensorflow: 批标准化(Batch Normalization)
  2. 用tolower()和toupper()来实现对string进行大小写转换
  3. C++使用Merge Sort排序计数反转的实现算法(附完整源码)
  4. 【渝粤教育】国家开放大学2018年春季 0703-21T经济学基础 参考试题
  5. 面试官问我:解释一下Dubbo服务暴露
  6. 插入排序 - python实现
  7. 消息中间件学习总结(12)——Kafka与RocketMQ的多Topic对性能稳定性的影响比较分析
  8. php怎么限制文章标题的字数,文章标题在WordPress中显示的长度即字数如何限制呢?...
  9. python实现协同过滤算法
  10. 修订的GRE分类词汇(截屏版)
  11. 打造爆款关键词选择10种方法
  12. 各纬度气候分布图_高中地理丨各种气候类型分布图+气候问题全总结,再也不怕搞混了!...
  13. Hadoop:INFO mapreduce.Job: Running job
  14. 花了我一个晚上时间整理的Python魂斗罗小游戏源代码
  15. 华为HCNA实验学习
  16. day05匿名函数,内置函数,二分法,递归,模块
  17. 《万字长文》-吃透Docker-进阶篇
  18. let , const , var , 的区别
  19. oracle时间回溯,关于Oracle降序索引的定意及回溯
  20. MIPS 五级流水线

热门文章

  1. 从零开始,轻松打造你的聊天机器人
  2. 【Visual C++】游戏开发笔记二十六 DirectX 11各组件的介绍 第一个DirectX 11 Demo的创建
  3. pandas----difference()
  4. 无线路由器故障排除与解决方案
  5. 【学习OpenCV】基于opencv的直线和曲线拟合与绘制(最小二乘法)
  6. 一文教你弄懂Flink核心功能和原理
  7. php 固定人数拼手气_PHP 拼手气红包 分配红包金额
  8. smarty之foreach和section
  9. 室内装修风水 之 堂前聚水法 - oralusa.com
  10. [附源码]SSM计算机毕业设计时事资讯平台JAVA