如何在非Spring Boot的Spring Web应用中覆盖第三方Jar中的Bean定义?
看起来你遇到的问题是Spring优先使用了第三方Jar里的dbprops Bean定义,而不是你自己在dao.xml里的覆盖版本。别着急,我们一步步来解决这个问题。
首先得明确Spring加载Bean定义的核心规则:当多个配置文件中存在相同id的Bean时,后加载的配置文件里的Bean定义会覆盖先加载的那个。理论上只要你的dao.xml在dao-common.xml之后被加载,就能实现覆盖,但显然你的情况没生效,我们来排查和解决:
一、先确认配置文件的加载顺序与有效性
先检查你的contextConfigLocation配置顺序:
<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:dao-common.xml classpath:dao.xml </param-value> </context-param>
这里dao-common.xml在前、dao.xml在后,按道理dao.xml的Bean应该覆盖前者,但如果没生效,先确认两个关键点:
- 你的
dao.xml是否真的被Spring加载了?可以打开Spring的DEBUG日志,搜索Loading XML bean definitions from class path resource [dao.xml],如果能找到这条日志,说明文件被正确加载;如果找不到,检查文件路径是否正确(比如是否放在WEB-INF/classes目录下,保证classpath能访问到)。 - 检查Bean的
id和class是否完全一致:确保你在dao.xml里的Beanid确实是dbprops,类名DBProps(包括完整包名)和第三方Jar里的定义完全匹配,别因为大小写或包名差异导致Spring识别为不同Bean。
二、用primary属性强制优先选择你的Bean
如果上面的顺序没问题但还是没生效,可以给你自己的Bean加上primary="true"属性,明确告诉Spring:当存在多个同类型Bean时,优先选择这个:
<bean id="dbprops" class="DBProps" primary="true"> <constructor-arg value="something else" /> </bean>
这个属性的作用是,即使存在同id的Bean定义,Spring在注入DBProps类型的Bean时,也会优先挑选标记为primary的实例,能有效强制覆盖第三方的定义。
三、调整配置文件加载顺序(极端场景)
如果前面的方法都没效果,可以尝试把dao.xml放在dao-common.xml前面加载:
<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:dao.xml classpath:dao-common.xml </param-value> </context-param>
正常情况下后加载的会覆盖先加载的,但如果第三方Jar里的Bean定义有特殊处理(比如通过BeanPostProcessor提前初始化),调整顺序可能会解决问题。不过这种情况比较少见,优先用前面的方法。
四、排查是否存在多个Spring上下文
Web应用里有时会存在多个Spring上下文:比如ContextLoaderListener加载的根上下文,和DispatcherServlet加载的子上下文。如果第三方Jar的配置被加载到了子上下文,而你的dao.xml只在根上下文,那子上下文的Bean会覆盖根上下文的。
这种情况下,检查你的DispatcherServlet配置:
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:servlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
如果servlet-context.xml里也导入了dao-common.xml,那你需要把dao.xml也加到这里的contextConfigLocation里,并且放在dao-common.xml之后,保证子上下文里你的Bean能覆盖第三方的。
备注:内容来源于stack exchange,提问作者Priyshrm

