我有一个 Spring Boot 应用程序,最近从 1.x.x 迁移到 2.x.x。我正在使用一些第 3 方库/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?请记住,这些是 3rd 方库,我无法编辑。
我正在包含 main 方法的 Java 类上使用
@SpringBootApplication
。
首先,应用程序中有两个类
PrometheusServletAutoConfiguration
是一种代码味道,我首先会问自己为什么有两个类。理想的解决方案是拥有一个。
至于Spring异常,可能是因为Spring自动检测到两个带有
@Configuration
注释的类,并生成两个同名的bean(默认情况下,bean名称是根据类名称计算的)。您可以覆盖其中一个类的 bean 名称:
@Configuration("myPrometheusServletAutoConfig")
public class PrometheusServletAutoConfiguration {
这应该是一条评论,但对于这样的评论来说太长了。
我还没有测试过这个(如果它不起作用,我会删除这个答案),但是你可以尝试吗?你可以做
// 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();
}
然后运行您的应用程序。