Spring Boot 应用程序“bean 类的 bean 名称与现有冲突” - 如何从 3rd 方库/依赖项中排除包/类?

Posted

技术标签:

【中文标题】Spring Boot 应用程序“bean 类的 bean 名称与现有冲突” - 如何从 3rd 方库/依赖项中排除包/类?【英文标题】:Spring Boot app "bean name for bean class conflicts with existing" - how to exclude package/Class from 3rd party library/dependency? 【发布时间】:2021-05-19 19:55:33 【问题描述】:

我有一个最近从 1.x.x 迁移到 2.x.x 的 Spring Boot 应用程序。我正在使用一些 3rd 方库/JAR 来使用 Prometheus 记录一些指标。

问题是我有 (2) 个名为 PrometheusServletAutoConfiguration 的 Java 类,它们都用 @Configuration 注释,我得到了臭名昭著的 Spring 异常:

org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'prometheusServletAutoConfiguration' for bean class [com.my.package.path1.PrometheusServletAutoConfiguration] conflicts with existing, non-compatible bean definition of same name and class [com.my.package.path2.PrometheusServletAutoConfiguration]

如您所见,它们的 FQDN 确实略有不同(完全限定的域名,或包路径,我为本示例简化了它,如您所见),但主类名称相同,所以我认为 Spring 正在尝试找出要创建和失败的 Bean。这完全让我感到困惑,我在 IntelliJ 中使用 Spring 1.x.x 查看了旧分支代码中的代码/库,并且 从未抛出此异常(它在 Spring 1.x.x 中是否被忽略了? ?)。我还会注意到代码编译良好,但在运行时失败(有道理)

这里是最好的分辨率吗?我是否应该告诉 Spring 不要扫描这些类 FQDN 之一,以便它只在应用程序上下文中创建 1 个 bean?请记住,这些是第 3 方库,我无法编辑

我在包含 main 方法的 Java 类上使用 @SpringBootApplication

【问题讨论】:

这是一个有趣的问题,很遗憾你没有回来说我的回答是否对你有用。 【参考方案1】:

首先,在应用程序中有两个类PrometheusServletAutoConfiguration 是一种代码味道,我会首先问自己为什么有两个类。理想的解决方案是拥有一个。

至于Spring的异常,可能是因为Spring自动检测到了@Configuration注解的两个类,生成了两个同名的bean(默认bean的名字是根据类名计算出来的)。您可以覆盖其中一个类的 bean 名称:

@Configuration("myPrometheusServletAutoConfig")
public class PrometheusServletAutoConfiguration 

相关:Annotation-specified bean name conflicts with existing, non-compatible bean def

【讨论】:

@M A 这是一个遗留应用程序,两个名称冲突的类是依赖项——如果它是一个外部 JAR 被拉入我的项目,我真的可以覆盖它吗? @ennth 你真的需要两者吗?如果没有,您可以排除其中之一:***.com/questions/44255224/…【参考方案2】:

这应该是一个评论,但它太长了。

我没有测试过这个(如果它不起作用,我会删除这个答案),但是你可以试试吗?你可以这样做

// extend one of the configs
@Configuration(value = "myPrometheusServletAutoConfig")
public class CopyConfig extends com.my.package.path2.PrometheusServletAutoConfiguration 

然后定义一个BeanPostProcessor:

public class MyPostProcessor implements BeanPostProcessor 
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException 
        if(bean.getClass().equals(com.my.package.path2.PrometheusServletAutoConfiguration.class))
            return new CopyConfig();
        
        return bean;
    

并在你的上下文中注册这个:

@Bean
public MyPostProcessor customBeanFactory() 
    return new MyPostProcessor();

然后运行您的应用程序。

【讨论】:

以上是关于Spring Boot 应用程序“bean 类的 bean 名称与现有冲突” - 如何从 3rd 方库/依赖项中排除包/类?的主要内容,如果未能解决你的问题,请参考以下文章

Spring 学习历程

Spring 学习指南 第三章 bean的配置 (未完结)

Spring_Spring与IoC_Bean的装配

7 -- Spring的基本用法 -- 7...

Spring框架第一篇之Bean的装配

springboot入门(HelloWorld)