springboot-啟動bean沖突的解決
啟動bean沖突
在一次啟動中遇到了bean沖突的問題,提示存在兩個名稱重復(fù)的bean
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.test.api.Application]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'healthCheckController' for bean class [com.test.datahub.controller.HealthCheckController] conflicts with existing, non-compatible bean definition of same name and class [com.test.api.controller.HealthCheckController]
項目中包括多個模塊,其中A、B兩個模塊都有同一個類:
HealthCheckController,檢查更改信息發(fā)現(xiàn),不知道誰在A模塊添加了B模塊的依賴,造成了這一問題,刪除后解決
? ? ? ? <dependency> ? ? ? ? ? ? <groupId>com.test</groupId> ? ? ? ? ? ? <artifactId>B</artifactId> ? ? ? ? ? ? <version>1.0.0-SNAPSHOT</version> ? ? ? ? </dependency>
啟動提示bean重復(fù)問題
先說結(jié)論
只需要在@FeignClient注解的contextId屬性上加上獨一的標示,即可解決問題
原理
是因為注冊feignClient的時候會注冊ClientConfiguration,參考代碼如下
public void registerFeignClients(AnnotationMetadata metadata, ? ? ? BeanDefinitionRegistry registry) { ? ?//...此處省略部分代碼 ? ?// ? ?for (String basePackage : basePackages) { ? ? ? Set<BeanDefinition> candidateComponents = scanner ? ? ? ? ? ? .findCandidateComponents(basePackage); ? ? ? for (BeanDefinition candidateComponent : candidateComponents) { ? ? ? ? ?if (candidateComponent instanceof AnnotatedBeanDefinition) { ? ? ? ? ? ? // verify annotated class is an interface ? ? ? ? ? ? //...省略部分代碼 ? ? ? ? ? ? ? //這塊是把注解上的所有屬性封裝到map上 ? ? ? ? ? ? Map<String, Object> attributes = annotationMetadata ? ? ? ? ? ? .getAnnotationAttributes( ? ? ? ? ? ? FeignClient.class.getCanonicalName()); ? ? ? ? ? ? ? //這兩個重點方法請看下面代碼塊 ? ? ? ? ? ? ? //獲取該feignClient的名字(重點關(guān)注該方法) ? ? ? ? ? ? String name = getClientName(attributes); ? ? ? ? ? ? ? //此方法就是spring注入beanDefination的步驟(重點關(guān)注該方法) ? ? ? ? ? ? registerClientConfiguration(registry, name, ? ? ? ? ? ? ? ? ? attributes.get("configuration")); ? ? ? ? ? ? ? registerFeignClient(registry, annotationMetadata, attributes); ? ? ? ? ?} ? ? ? } ? ?} }
上面的兩處重點方法, 請看此處
//@param client 這個map就是通過上面的注解屬性轉(zhuǎn)map得到的 private String getClientName(Map<String, Object> client) { ? ?if (client == null) { ? ? ? return null; ? ?} ? ?//如果從contextId獲取到名字,那么value有值的 ? ?String value = (String) client.get("contextId"); ? ?//如果value有值,那么如下3個if條件都不會走,所以contextId唯一就可以做到bean不重復(fù), ? ?//如果value沒有值,就會取value,因為多個client的serverName都是一樣的,那么就會出現(xiàn)重復(fù)bean ? ?if (!StringUtils.hasText(value)) { ? ? ? value = (String) client.get("value"); ? ?} ? ?if (!StringUtils.hasText(value)) { ? ? ? value = (String) client.get("name"); ? ?} ? ?if (!StringUtils.hasText(value)) { ? ? ? value = (String) client.get("serviceId"); ? ?} ? ?if (StringUtils.hasText(value)) { ? ? ? return value; ? ?} ? ? ?throw new IllegalStateException("Either 'name' or 'value' must be provided in @" ? ? ? ? ?+ FeignClient.class.getSimpleName()); } ? private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, ? ? ? Object configuration) { ? ?BeanDefinitionBuilder builder = BeanDefinitionBuilder ? ? ? ? ?.genericBeanDefinition(FeignClientSpecification.class); ? ?builder.addConstructorArgValue(name); ? ?builder.addConstructorArgValue(configuration); ? ?//在這個位置,創(chuàng)建beanDefinition,但是他創(chuàng)建的名字格式可以看出,唯一改變變量就是name,這個name就是上面看到的那個方法獲取的 ? ?registry.registerBeanDefinition( ? ? ? ? ?name + "." + FeignClientSpecification.class.getSimpleName(), ? ? ? ? ?builder.getBeanDefinition()); }
以上就是feign導(dǎo)致的springBean重復(fù)問題的解釋,僅上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring Boot實現(xiàn)郵件服務(wù)(附:常見郵箱的配置)
這篇文章主要給大家介紹了關(guān)于Spring Boot實現(xiàn)郵件服務(wù)的相關(guān)資料,文中還附上了常見郵箱的配置,通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-12-12Java中通過ZipOutputStream類如何將多個文件打成zip
ZipOutputStream?是Java中用于創(chuàng)建ZIP文件的類,它是?java.util.zip?包中的一部分,通過使用?ZipOutputStream?,可以將多個文件壓縮到一個ZIP文件中,這篇文章主要介紹了Java中(ZipOutputStream)如何將多個文件打成zip,需要的朋友可以參考下2023-09-09解析Java中PriorityQueue優(yōu)先級隊列結(jié)構(gòu)的源碼及用法
優(yōu)先級隊列是一種隊列結(jié)構(gòu),是0個或多個元素的集合,每個元素都有一個優(yōu)先權(quán),PriorityQueue被內(nèi)置于JDK中,本文就來解析Java中PriorityQueue優(yōu)先級隊列結(jié)構(gòu)的源碼及用法.2016-05-05IDEA連接postgressql數(shù)據(jù)庫操作
這篇文章主要介紹了IDEA連接postgressql數(shù)據(jù)庫操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08Springmvc實現(xiàn)文件下載2種實現(xiàn)方法
這篇文章主要介紹了Springmvc實現(xiàn)文件下載2種實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03