spring.main.allow-bean-definition-overriding = true是不好的做法吗

时间:2019-05-17 14:56:48

标签: java spring spring-boot

我正在构建一个Spring Boot Rest API服务器,以在更强大的框架上移植旧版应用程序。那是我使用这些技术的第一个项目。到目前为止,我已经使用2个API构建了概念验证,它们可以回答“ Hello world!”。在JSON中。一个是开放的,另一个是由OAuth2保护的。我已经将安全性调整到了要求。

我还使用Rest-Assured进行集成测试,并使用Spring MockMvc进行单元测试,从而构建了一个强大的测试结构,因此我有信心准备开始使用TDD方法实现真正​​的API。

我们正在使用Maven。我的问题是,一旦我对现有工件有了依赖性,就会得到以下堆栈。我知道这意味着什么,但是我们的代码库很大,我无法确定它的来源。当我问Google这个问题时,我经常发现结果只是建议将spring.main.allow-bean-definition-overriding=true添加到我的媒体资源中。这难道不是扫地出门的问题吗?我猜有一个很好的理由解释为什么Spring默认情况下不允许这样做。仅凭便利的应用程序属性忽略该错误可能会带来什么后果?

堆栈:

*************************** APPLICATION FAILED TO START
***************************

Description:

The bean 'org.springframework.transaction.config.internalTransactionAdvisor', defined in class path resource [org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.class], could not be registered. A bean with that name has already been defined in null and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

[WARNING]  java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:498)
    at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run (AbstractRunMojo.java:558)
    at java.lang.Thread.run (Thread.java:748) Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'org.springframework.transaction.config.internalTransactionAdvisor' defined in class path resource [org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.class]: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration; factoryMethodName=transactionAdvisor; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.class]] for bean 'org.springframework.transaction.config.internalTransactionAdvisor': There is already [Root bean: class [org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] bound.
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition (DefaultListableBeanFactory.java:897)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod (ConfigurationClassBeanDefinitionReader.java:274)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass (ConfigurationClassBeanDefinitionReader.java:141)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions (ConfigurationClassBeanDefinitionReader.java:117)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions (ConfigurationClassPostProcessor.java:327)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry (ConfigurationClassPostProcessor.java:232)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors (PostProcessorRegistrationDelegate.java:275)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors (PostProcessorRegistrationDelegate.java:95)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors (AbstractApplicationContext.java:705)
    at org.springframework.context.support.AbstractApplicationContext.refresh (AbstractApplicationContext.java:531)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh (ServletWebServerApplicationContext.java:142)
    at org.springframework.boot.SpringApplication.refresh (SpringApplication.java:775)
    at org.springframework.boot.SpringApplication.refreshContext (SpringApplication.java:397)
    at org.springframework.boot.SpringApplication.run (SpringApplication.java:316)
    at org.springframework.boot.SpringApplication.run (SpringApplication.java:1260)
    at org.springframework.boot.SpringApplication.run (SpringApplication.java:1248)
    at ca.mycompany.oav.ResourceServerApplication.main (ResourceServerApplication.java:22)
    at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:498)
    at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run (AbstractRunMojo.java:558)
    at java.lang.Thread.run (Thread.java:748)

3 个答案:

答案 0 :(得分:0)

需要注意的是:通过添加这个,很难猜测哪个 bean 将具有优先级,因为 bean 创建顺序是由主要在运行时影响的依赖关系决定的。因此,允许 bean 覆盖除非我们足够了解 bean 的依赖层次结构,否则可能会产生意外行为。

Reference

答案 1 :(得分:0)

答案是

<块引用>

不,尽量不要使用覆盖。但有时可能(但要谨慎)

为了更好地理解这一点,

当您启动应用程序时,Spring Boot 会自动加载许多 bean(以提供开箱即用的功能),有些可能需要,有些可能不需要。我们有两个选择

选项 1:

  1. 让 Spring Boot 加载功能
  2. 您稍后覆盖

选项 2:

  1. 要求 Spring Boot 不要加载您不需要的内容。
  2. 只需添加您自己的 bean

示例用例

Spring Boot 提供了带有 ConfigServicePropertySourceLocator 的开箱即用的云配置。在实时场景中,我们将使用我们自己的安全配置服务器而不是默认配置服务器。

选项 1:

  1. 让 Spring Boot 加载 ConfigServicePropertySourceLocator Bean
  2. 通过指定 spring.main.allow-bean-definition-overriding=true 启用覆盖
  3. 定义自定义 Bean,但请确保添加 @Order、@Primary 等

选项 2:

  1. 通过添加 spring.cloud.config.enabled=false 来询问 Spring Boot 不加载 ConfigServicePropertySourceLocator
  2. 只需定义您的自定义 Bean。

您节省了启动时间,代码看起来也很干净。

参考:https://github.com/spring-cloud/spring-cloud-config/issues/177

答案 2 :(得分:0)

spring.main.allow-bean-definition-overriding=true 涉及使用与现有 bean 相同的 bean 名称覆盖 bean。如果 bean 在您自己的代码中,您可以随时更改 bean 名称(如果使用 @Bean,名称默认为方法名称,或 @Component 的类名称;但有不同的设置 bean 名称的方法,请查看文档)。

因此,设置此标志的唯一合理(据我所知)原因是如果您无法控制(即来自第 3 方代码)的多个 bean 加载了相同的名称。