user327961
user327961

Reputation: 2490

Is spring.main.allow-bean-definition-overriding=true a bad practice

I am building a Spring Boot Rest API server to port a legacy application on a more robust framework. That is my first project using those technologies. So far I have built a proof of concept with 2 API that reply "Hello world!" in JSON. One is open and the other is secured with OAuth2. I am done tuning the security up to the requirement.

I have also built a strong test structure using a combination of Rest-Assured for integration tests and Spring MockMvc for unit tests, so I am confident I am ready to start implementing real API using a TDD approach.

We are using Maven. My problem is that as soon as I had a dependency with our existing artifacts, I get the following stack. I understand what it means but our codebase is huge and I can't find out where this comes from. When I ask Google about this problem, I often find result simply suggesting to add spring.main.allow-bean-definition-overriding=true to my properties. Isn't this just sweeping the problem under the rug ? I would guess there is a very good reason why Spring doesn't allow this by default. What are the possible consequences of simply ignoring that error with a convenient 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)

Upvotes: 5

Views: 13001

Answers (3)

jhyot
jhyot

Reputation: 3955

spring.main.allow-bean-definition-overriding=true concerns overriding beans using the same bean name as an existing bean. If the bean is in your own code, you can always just change the bean name (if using @Bean, the name is by default the method name, or the class name for @Component; but there are different ways to set the bean name, check the docs).

So the only reasonable (as far as I can think) reason to set this flag is if multiple beans that you don't control (i.e. from 3rd party code) are loaded with the same name.

Upvotes: 1

Answer is

No don't use overriding as much as possible. But at times may be (but with caution)

To understand this better,

When you start the Application, Spring Boot auto-loads many beans (to provide out-of-the-box functionalities) some may be required some may not be. There are two options we have

Option #1:

  1. Let Spring Boot Load the functionality
  2. You later override

Option #2:

  1. Ask Spring Boot not to load what you don't need.
  2. Just add your own bean

Example Use-case

Spring Boot provides out of the box Cloud Configuration with ConfigServicePropertySourceLocator. in a realtime scenario, we will have our own secured config server to use instead of the default one.

Option #1:

  1. Let Spring Boot Load ConfigServicePropertySourceLocator Bean
  2. Enable overriding by specifying spring.main.allow-bean-definition-overriding=true
  3. Define you custom Bean, But make sure you add @Order, @Primary etc.

Option #2:

  1. Ask Spring Boot not load ConfigServicePropertySourceLocator by adding spring.cloud.config.enabled=false
  2. Just Define you custom Bean.

You save startup time also code looks clean.

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

Upvotes: 0

Muhammad Waqas Dilawar
Muhammad Waqas Dilawar

Reputation: 2322

Just to be aware that: by adding this, it is difficult to guess which bean will have priority because the bean creation order is determined by dependency relationships mostly influenced in runtime. Therefore, allowing bean overriding can produce unexpected behavior unless we know the dependency hierarchy of our beans well enough.

Reference

Upvotes: 7

Related Questions