如何在 Spring Boot 2.1.0 启动器配置中将 spring.main.allow-bean-definition-overriding 设置为 true

Posted

技术标签:

【中文标题】如何在 Spring Boot 2.1.0 启动器配置中将 spring.main.allow-bean-definition-overriding 设置为 true【英文标题】:How to set spring.main.allow-bean-definition-overriding to true in a Spring boot 2.1.0 starter configuration 【发布时间】:2019-04-26 07:33:03 【问题描述】:

我维护了一个 spring-boot-starter 来定制返回的错误属性,例如,一个未知的端点被调用。 这是通过覆盖 org.springframework.boot.web.servlet.error.ErrorAttributes bean 来完成的。

在 2.0.6 中一切正常,但 2.1.0 disables bean overriding by default,导致启动器现在失败并显示以下消息。

类中定义的名称为“errorAttributes”的无效 bean 定义 路径资源 [com/mycompany/springboot/starter/config/ErrorsConfig.class]:不能 注册bean定义[根bean:类[null];范围=; 摘要=假;懒惰初始化=假;自动线模式=3;依赖检查=0; 自动接线候选=真;主要=假; factoryBeanName=com.mycompany.springboot.starter.config.ErrorsConfig; factoryMethodName=errorAttributes;初始化方法名=空; destroyMethodName=(推断);在类路径资源中定义 [com/mycompany/springboot/starter/config/ErrorsConfig.class]] 用于 bean 'errorAttributes': 已经有 [Root bean: class [null];范围=; 摘要=假;懒惰初始化=假;自动线模式=3;依赖检查=0; 自动接线候选=真;主要=假; factoryBeanName=org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration; factoryMethodName=errorAttributes;初始化方法名=空; destroyMethodName=(推断);在类路径资源中定义 [org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.class]] 绑定

如文档中所述,将 spring.main.allow-bean-definition-overriding 属性设置为 true 可以解决问题。 我的问题是如何在启动器中(我不希望启动器的用户必须更改他们的 application.properties 文件,以获取特定于我的启动器的内容)?

我尝试使用在该文件中定义的属性对我的@Configuration 进行@PropertySource("classpath:/com/mycompany/starter/application.properties") 注释,但它不起作用。

我错过了什么?有什么方法可以让我的配置覆盖该 bean?

这是配置的(简化的)源代码:

@Configuration
@PropertySource("classpath:/com/mycompany/starter/application.properties")
public class ErrorsConfig 
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @Bean
    public ErrorAttributes errorAttributes() 
        return new DefaultErrorAttributes() 
            @SuppressWarnings("unchecked")
            @Override
            public Map<String, Object> getErrorAttributes(WebRequest request, boolean includeStackTrace) 
                Map<String, Object> errorAttributes = super.getErrorAttributes(request, includeStackTrace);
                // CustomeError is a (simplified) bean of the error attributes we should return.
                CustomError err = new CustomError("myErrorCode", (String) errorAttributes.get("error"));
                return OBJECT_MAPPER.convertValue(err, Map.class);
            
        ;
    

我的资源文件 com/mycompany/starter/application.properties 包含

spring.main.allow-bean-definition-overriding=true

【问题讨论】:

【参考方案1】:

Spring Boot 的 ErrorAttributes bean 由 ErrorMvcAutoConfiguration 定义。它带有@ConditionalOnMissingBean 注释,因此如果已经定义了ErrorAttributes bean,它将退出。由于ErrorsConfig 类定义的bean 试图覆盖Boot 的ErrorAttributes bean,而不是使其退出,因此必须在Boot 的ErrorMvcAutoConfiguration 类之后处理您的ErrorsConfig 类。这意味着您的启动器中存在排序问题。

可以使用@AutoConfigureBefore@AutoConfigureAfter 控制处理自动配置类的顺序。假设ErrorsConfig 本身是在spring.factories 中注册的自动配置类,您可以通过使用@AutoConfigureBefore(ErrorMvcAutoConfiguration.class) 对其进行注释来解决您的问题。有了这个更改,ErrorsConfig 将在 ErrorMvcAutoConfiguration 尝试这样做之前定义其 ErrorAttributes bean,这将导致 Boot 的 ErrorsAttribute bean 的自动配置退出。

【讨论】:

Andy:如果 ErrorsConfig 不是自动配置怎么办?是否有类似的机制,还是我必须使用唯一名称或排除 ErrorMvcAutoConfiguration? 正常配置应该在任何自动配置之前运行。如果您没有编写自己的自动配置,则不应在此处解决问题。 我创建了一个小示例来显示 spring-batch 的行为:github.com/JorgenRingen/… 我正在添加 @EnableBatchProcessing 并配置我自己的 JobLauncher bean,其名称与 spring-batch 自动配置使用的名称相同并获得错误消息,告知类路径中已存在具有该名称的 bean(让我知道是否应该在 github 上提出问题) @jorgen.ringen 这个问题确实与这个问题和答案无关。 Batch 期望 JobLauncher 通过 BatchConfigurer bean 提供,而不是直接配置为 bean。【参考方案2】:

更简单的解决方案是在application.properties 中添加此属性spring.main.allow-bean-definition-overriding=true

Reference

【讨论】:

以上是关于如何在 Spring Boot 2.1.0 启动器配置中将 spring.main.allow-bean-definition-overriding 设置为 true的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 2.0:Spring Boot 如何解决项目启动时初始化资源

如何在不依赖 MongoDB 的情况下启动 spring-boot 应用程序?

如何在spring boot启动期间关闭应用程序

Spring boot工程如何启用热启动功能

在我的 spring-boot 应用程序启动之前,我如何等待数据库容器启动

如何在 spring-boot 应用程序启动期间创建许多 kafka 主题?