服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - springboot-启动bean冲突的解决

springboot-启动bean冲突的解决

2022-10-21 15:06鬼~离未罔两 Java教程

这篇文章主要介绍了springboot-启动bean冲突的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

启动bean冲突

在一次启动中遇到了bean冲突的问题,提示存在两个名称重复的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,检查更改信息发现,不知道谁在A模块添加了B模块的依赖,造成了这一问题,删除后解决

?
1
2
3
4
5
        <dependency>
            <groupId>com.test</groupId>
            <artifactId>B</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>

启动提示bean重复问题

先说结论

只需要在@FeignClient注解的contextId属性上加上独一的标示,即可解决问题

原理

是因为注册feignClient的时候会注册ClientConfiguration,参考代码如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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的名字(重点关注该方法)
            String name = getClientName(attributes);
 
            //此方法就是spring注入beanDefination的步骤(重点关注该方法)
            registerClientConfiguration(registry, name,
                  attributes.get("configuration"));
 
            registerFeignClient(registry, annotationMetadata, attributes);
         }
      }
   }
}

上面的两处重点方法, 请看此处

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//@param client 这个map就是通过上面的注解属性转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不重复,
   //如果value没有值,就会取value,因为多个client的serverName都是一样的,那么就会出现重复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);
   //在这个位置,创建beanDefinition,但是他创建的名字格式可以看出,唯一改变变量就是name,这个name就是上面看到的那个方法获取的
   registry.registerBeanDefinition(
         name + "." + FeignClientSpecification.class.getSimpleName(),
         builder.getBeanDefinition());
}

以上就是feign导致的springBean重复问题的解释,仅上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/sky_flying1/article/details/97778377

延伸 · 阅读

精彩推荐