springboot項(xiàng)目中出現(xiàn)同名bean異常報(bào)錯(cuò)的解決方法
前言
最近業(yè)務(wù)部門接手供方的項(xiàng)目過(guò)來(lái)二開,其中有個(gè)認(rèn)證實(shí)現(xiàn)因?yàn)闃I(yè)務(wù)需要,需要替換原有供方實(shí)現(xiàn)的邏輯。大概偽代碼如下。供方提供的接口以及默認(rèn)實(shí)現(xiàn)形如下
public interface AuthCodeService {
default Boolean check() {
return true;
}
}
@Service("authCodeService")
public class AuthCodeImpl implements AuthCodeService {
public Boolean check() {
// doBiz
return true;
}
}
業(yè)務(wù)的替換實(shí)現(xiàn)如下
@Service
public class BizAuthCodeImpl implements AuthCodeService {
public Boolean check() {
// doOtherBiz
return true;
}
}
然而項(xiàng)目運(yùn)行的時(shí)候,發(fā)現(xiàn)走的認(rèn)證邏輯始終是供方的邏輯,而非業(yè)務(wù)重寫后的邏輯。
平時(shí)因?yàn)楦鷺I(yè)務(wù)的技術(shù)負(fù)責(zé)人走得比較近,他就私下找我交流一下思路。一開始我給他提的建議是說(shuō)在你定制的業(yè)務(wù)類上加@Primary試下,他說(shuō)他加了但沒(méi)效果。
于是我就跟他說(shuō)不然你直接改供方源碼的默認(rèn)實(shí)現(xiàn),他給的答復(fù)供方?jīng)]提供源碼,只提供jar。我就跟他說(shuō),這也可以改,你項(xiàng)目創(chuàng)建一個(gè)和供方實(shí)現(xiàn)一模一樣的類,就是包名和類名一模一樣,利用類的加載順序?qū)崿F(xiàn)。技術(shù)負(fù)責(zé)人又覺(jué)得這樣不好。
后面那個(gè)技術(shù)負(fù)責(zé)人想了一個(gè)方式,就是他將業(yè)務(wù)定制bean名稱和供方提供的bean名稱一樣,形如下
@Service("authCodeService")
public class BizAuthCodeImpl implements AuthCodeService {
public Boolean check() {
// doOtherBiz
return true;
}
}
然后項(xiàng)目啟動(dòng),直接報(bào)了如下錯(cuò)
org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'authCodeService' for bean class
他就跟我說(shuō)這個(gè)異常怎么修復(fù),鋪墊了這么久,引來(lái)了今天要聊的話題,同名bean異常報(bào)錯(cuò)如何修復(fù)
解決思路
首先拋出一個(gè)觀點(diǎn),在同個(gè)spring容器中,是不能出現(xiàn)同名的bean,因此解決的思路要么搞成不同的spring容器,要么就是排除多個(gè)同名的bean,只保留自己想要的那個(gè)。要么就是將bean改個(gè)名字。今天介紹的思路就是排除同名bean,只保留自己想要的bean
實(shí)現(xiàn)方法
1、方法一:通過(guò)@ComponentScan進(jìn)行排除
示例配置
在springboot的啟動(dòng)類上加上形如下內(nèi)容
@ComponentScan(basePackages = {"com.github.lybgeek"},excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = AuthCodeImpl.class)})
這邊有個(gè)注意點(diǎn)是當(dāng)你啟動(dòng)類上同時(shí)存在@SpringBootApplication和@ComponentScan注解時(shí),@ComponentScan注解指定的掃描包路徑會(huì)覆蓋@SpringBootApplication的包路徑。
我將第一種方案告訴業(yè)務(wù)技術(shù)負(fù)責(zé)人后,他試了一下,果然沒(méi)報(bào)錯(cuò),但是后面出現(xiàn)一個(gè)問(wèn)題,他說(shuō)@SpringBootApplication的屬性exclude()失效了,導(dǎo)致他項(xiàng)目要排除的自動(dòng)裝配類失效了。于是就有了第二種方案
2、方法二:自定義TypeExcludeFilter
我們點(diǎn)開@SpringBootApplication,可以看到如下內(nèi)容
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
既然@SpringBootApplication和@ComponentScan同時(shí)標(biāo)注在啟動(dòng)類上會(huì)有一定沖突,我們就遵循@SpringBootApplication提供的擴(kuò)展方案就好了,自己寫一個(gè)TypeExcludeFilter進(jìn)行排除
實(shí)現(xiàn)步驟
1、自定義TypeExcludeFilter
public class CustomTypeExcludeFilter extends TypeExcludeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
String className = metadataReader.getClassMetadata().getClassName();
return AuthCodeImpl.class.getName().equals(className);
}
}
2、將自定義TypeExcludeFilter注入到spring容器 中
這邊有個(gè)特別需要注意的細(xì)節(jié)點(diǎn),因?yàn)門ypeExcludeFilter是要排除bean的,因此他注入的時(shí)機(jī)至少要在其他bean注入之前,具體來(lái)說(shuō)就是在容器上下文refresh執(zhí)行之前,就得完成注入。在refresh之前執(zhí)行的擴(kuò)展點(diǎn)有很多,我們就挑一個(gè),我們以實(shí)現(xiàn)ApplicationContextInitializer為例
public class CustomTypeExcludeFilterApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(CustomTypeExcludeFilter.class);
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
defaultListableBeanFactory.registerBeanDefinition("customTypeExcludeFilter",beanDefinition);
}
}
3、將ApplicationContextInitializer 的實(shí)現(xiàn)類放在/META-INF/spring.factories
org.springframework.context.ApplicationContextInitializer=\ com.github.lybgeek.context.CustomTypeExcludeFilterApplicationContextInitializer
按照上面三步執(zhí)行,就可以排除自己想排除的bean
總結(jié)
當(dāng)項(xiàng)目中出現(xiàn)同名bean沖突時(shí),如果可以的話,就盡量換個(gè)其他bean名稱來(lái)解決
后面業(yè)務(wù)負(fù)責(zé)人并沒(méi)有采用我上述的方案,我們回歸業(yè)務(wù)負(fù)責(zé)人他們項(xiàng)目訴求,他們的需求是要他們自定義認(rèn)證的邏輯能生效,而非解決同名bean沖突。
業(yè)務(wù)負(fù)責(zé)人他們最后的方案是通過(guò)加@Primary注解解決,他之前加了覺(jué)得沒(méi)生效,是因?yàn)樗麄冺?xiàng)目引的自定義認(rèn)證邏輯的舊包,那個(gè)舊包沒(méi)加@Primary注解,后面把包升級(jí)就解決了
以上就是springboot項(xiàng)目中出現(xiàn)同名bean異常報(bào)錯(cuò)的解決方法的詳細(xì)內(nèi)容,更多關(guān)于springboot出現(xiàn)同名bean的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- springboot項(xiàng)目啟動(dòng)的時(shí)候,運(yùn)行main方法報(bào)錯(cuò)NoClassDefFoundError問(wèn)題
- 解決SpringBoot搭建MyBatisPlus中selectList遇到LambdaQueryWrapper報(bào)錯(cuò)問(wèn)題
- SpringBoot項(xiàng)目導(dǎo)入aliyun oss starter依賴后啟動(dòng)報(bào)錯(cuò)問(wèn)題
- SpringBoot 2.6.x整合springfox 3.0報(bào)錯(cuò)問(wèn)題及解決方案
- springboot連接neo4j報(bào)錯(cuò)的解決方案
相關(guān)文章
Springboot內(nèi)嵌tomcat應(yīng)用原理深入分析
懂得SpringBoot的童鞋應(yīng)該很清楚,不管應(yīng)用程序是屬于何種類型,都是一個(gè)Main方法走遍天下,對(duì)于web應(yīng)用,只需要引入spring-boot-starter-web中這個(gè)依賴,應(yīng)用程序就好像直接給我們來(lái)了個(gè)tomcat一樣,對(duì)于嵌入式Tomcat,其實(shí)也非常簡(jiǎn)單,就是調(diào)用Tomcat提供的外部類2022-09-09
java.lang.NoSuchMethodException: com.sun.proxy.$Proxy58.list
這篇文章主要介紹了java.lang.NoSuchMethodException: com.sun.proxy.$Proxy58.list錯(cuò)誤解決辦法的相關(guān)資料,需要的朋友可以參考下2016-12-12
springboot整合shiro登錄失敗次數(shù)限制功能的實(shí)現(xiàn)代碼
這篇文章主要介紹了springboot整合shiro-登錄失敗次數(shù)限制功能,實(shí)現(xiàn)此功能如果是防止壞人多次嘗試,破解密碼的情況,所以要限制用戶登錄嘗試次數(shù),需要的朋友可以參考下2018-09-09
Java中l(wèi)ength,length(),size()詳解及區(qū)別
這篇文章主要介紹了Java中l(wèi)ength,length(),size()詳解及區(qū)別的相關(guān)資料,需要的朋友可以參考下2016-11-11
Java工具類實(shí)現(xiàn)高效編寫報(bào)表
對(duì)于報(bào)表數(shù)據(jù)大部分情況下使用寫sql的方式為大屏/報(bào)表提供數(shù)據(jù)來(lái)源,但是對(duì)于某些復(fù)雜情況下僅僅使用sql無(wú)法實(shí)現(xiàn),這篇文章主要介紹了Java工具類實(shí)現(xiàn)高效編寫報(bào)表2022-11-11
Springboot整合Flowable6.x導(dǎo)出bpmn20的步驟詳解
這篇文章主要介紹了Springboot整合Flowable6.x導(dǎo)出bpmn20,Flowable流程引擎可用于部署B(yǎng)PMN 2.0流程定義,可以十分靈活地加入你的應(yīng)用/服務(wù)/構(gòu)架,本文給出兩種從flowable導(dǎo)出流程定義bpmn20.xml的方式,需要的朋友可以參考下2023-04-04
Java 實(shí)現(xiàn)瀏覽器下載文件及文件預(yù)覽
這篇文章主要介紹了Java 實(shí)現(xiàn)瀏覽器下載文件及文件預(yù)覽,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
使用純java config來(lái)配置spring mvc方式
這篇文章主要介紹了使用純java config來(lái)配置spring mvc方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
SpringBoot使用easy-captcha 實(shí)現(xiàn)驗(yàn)證碼登錄功能(解決思路)
文章介紹了如何使用Spring Boot和Easy-Captcha實(shí)現(xiàn)驗(yàn)證碼登錄功能,后端通過(guò)Easy-Captcha生成驗(yàn)證碼并存儲(chǔ)在Redis中,前端獲取驗(yàn)證碼并顯示給用戶,登錄時(shí),前端將用戶輸入的驗(yàn)證碼和標(biāo)識(shí)符發(fā)送到后端進(jìn)行驗(yàn)證,感興趣的朋友跟隨小編一起看看吧2025-02-02

