Is Allowing Bean Definition Overriding with spring.main.allow-bean-definition-overriding=true Considered a Negative Practice

In order to allow bean overriding, we can modify the “spring.main.allow-bean-definition-overriding” property to “true” in the “application.properties” file. This informs Spring Boot to permit bean overriding without altering any bean definitions. Nonetheless, if any of the bean definitions cannot be changed, configuring Spring Boot to allow bean overriding can serve as a solution.

Question:

My initial project utilizing new technologies involves developing a
Spring Boot
Rest API server. The aim is to transfer an older application to a more resilient framework. As of now, I have created a proof of concept comprising two APIs that both return “Hello world!” in JSON format. The first API is open, while the second is secured with OAuth2. I have currently completed the security adjustments to meet the necessary standards.

My test structure is robust, utilizing both
Rest-Assured
for integration testing and
Spring MockMvc
for
unit tests
. With this combination, I am fully prepared to implement actual API with a TDD methodology.

We utilize Maven, and upon adding a dependency with our existing artifacts, I encounter a stack trace that is difficult to trace due to the size of our codebase. Although I comprehend the issue, searching for a solution on Google results in suggestions to add

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

to my properties, which I believe is simply masking the problem. I assume Spring has valid reasons for not allowing this by default, and I am curious about the potential consequences of disregarding the error by adding it to the application properties.

The stack :

*************************** 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)


Solution 1:

Please note that when adding this, it may be challenging to determine which bean will take precedence since the order of bean creation is mainly influenced by runtime dependency relationships. As a result, incorporating
bean overriding
can result in unforeseen outcomes unless we have a thorough understanding of our bean’s dependency hierarchy.

Reference


Solution 2:

Answer is

Avoid excessive use of overriding, however, in certain situations it may be appropriate to use it with caution.

To understand this better,

Upon launching the Application, Spring Boot will load various beans automatically to offer pre-built features. While some of these beans may prove essential, others may not. In such cases, we are presented with two alternative courses of action.


Option #1:

  1. Allow Spring Boot to handle the functionality.
  2. You later override


Option #2:

  1. Optimize Spring Boot’s loading by specifying only the required components.
  2. Just add your own bean

Example Use-case

Spring Boot offers built-in Cloud Configuration using
configservicepropertysourcelocator
. However, in real-time situations, we might prefer utilizing our own secure configuration server instead of the default one.


Option #1:

  1. Allow the Bean ConfigServicePropertySourceLocator to be Loaded by Spring Boot.
  2. Specify

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

    to allow for overriding.
  3. When creating your own Bean, ensure that you include annotations such as @Order and @Primary.


Option #2:

  1. Add

    spring.cloud.config.enabled=false

    to prevent Spring Boot from loading ConfigServicePropertySourceLocator.
  2. Just Define you custom Bean.

By improving startup time, your code will not only run more efficiently, but also appear neater and more organized.

Here is a reference to an issue related to Spring Cloud Config on GitHub, which can provide more information and context.


Solution 3:


The issue discussed in

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

is related to replacing existing beans with a new one that has the same name. In case the bean is present in your code, you can modify the name of the bean. When using

@Bean

, the default bean name is the method name, and for

@Component

, it is the class name. However, there are various methods to set the bean name, which can be found in the documentation.

The flag should only be set if multiple beans with the same name, which are not under your control, are loaded. This is the most logical explanation I can come up with.

Frequently Asked Questions