Doubts about the background

Doubts description

Recently, in the process of development, a previous notation was found, similar to the following

@Configuration plus @bean creates a UserManager object whose userName is not null. The @Component also creates a UserManager object with a null userName

So when we inject a UserManager object into another object, which object is it?

Since the project has been live for a long time, there are no compilation errors and no runtime problems

I’m gonna go check with my colleagues, actually

It worked, and it did

So the question is: How many objects of type UserManager are there in the Spring container?

The Spring version of the Boot

The Spring Boot version used in the project is: 2.0.3.release

The scope of the object is the default value, which is a singleton

results

There are many ways to verify this, including debugging and source code to see how many UserManager objects there are in the Spring container, directly starting with the UserManager constructor to see which constructors are called, and so on

Let’s start with the constructor and see how many times the UserManager is instantiated

Only the parameter constructor is called; the no-parameter constructor is left untouched (not called at all).

Since the UserManager constructor is called only once, the previous question is which object is injected

@configuration and @bean create UserManager object where userName is not null

Why not @Component create UserManager object with null userName? Search the public vertical number: MarkerHub, follow the reply [vue] to get the beginning of the front and back end tutorial!

The source code parsing

@Configuration is closely related to @Component

So @Configuration can be scanned by Component

Including ConfigurationClassPostProcessor is closely related to @ the Configuration, the class hierarchy structure is as follows:

It implements the BeanFactoryPostProcessor and PriorityOrdered interfaces. For BeanFactoryPostProcessor, see:

www.cnblogs.com/youzhibing/…

Then we from AbstractApplicationContext refresh method invocation invokeBeanFactoryPostProcessors (the beanFactory) started, with the source code

QSL package and its subpackages UserConfig, UserController, and UserManager are scanned

Note that processing of the @bean has not yet started. The UserManager is scanned through the @Component; The UserManager in the beanDefinitionMap in the Spring container looks like this

The next step is important and has to do with the answer we want

The loop recursively processes UserConfig, UserController, and UserManager, encapsulating them all as a ConfigurationClass, and recursively scans the BeanDefinition

After the loop, let’s look at configClasses

BeanMethods in UserConfig bean definition information has a element [BeanMethod: name = userManager, declaringClass = com. Lee. QSL. Config. UserConfig]

And then we’ll move on and take a closer look at where the answer comes in

Did you find something? The @Component decorated UserManager definition is directly overridden by the @Configuration + @Bean decorated UserManager definition

Bean definition type also by ScannedGenericBeanDefinition replaced ConfigurationClassBeanDefinition

When a subsequent instance is created via BeanDefinition, it will naturally create the @Configuration + @Bean modified UserManager, which will reflect the parameterized constructor that called UserManager

The answer is now clear. Search the public vertical number: MarkerHub, follow the reply [vue] to get the beginning of the front and back end tutorial!

Spring actually gives a hint

The 2021-10-03 20:37:33. 13600-697 the INFO [the main] O.S.B.F.S.D efaultListableBeanFactory: Overriding bean definition for bean 'userManager' with a different definition: replacing [Generic bean: class [com.lee.qsl.manager.UserManager]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0;  dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null;  initMethodName=null; destroyMethodName=null;  defined in file [D:\qsl-project\spring-boot-bean-component\target\classes\com\lee\qsl\manager\UserManager.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true;  primary=false; factoryBeanName=userConfig; factoryMethodName=userManager; initMethodName=null;  destroyMethodName=(inferred); defined in class path resource [com/lee/qsl/config/UserConfig.class]]Copy the code

Only the log level is INFO, which is too inconspicuous

Spring Upgrade optimization

Perhaps the Spring team is aware that the INFO level is too unobvious, or that direct overwriting is not a sensible approach

So it was optimized in Spring 5.1.2.RELEASE (Spring Boot is 2.1.0.release)

Let’s see

You get an error when you start up, and Spring prompts you

The bean 'userManager', defined in class path resource [com/lee/qsl/config/UserConfig.class], could not be registered. A bean with that name has already been defined in file [D:\qsl-project\spring-boot-bean-component\target\classes\com\lee\qsl\manager\UserManager.class] and overriding is disabled.
Copy the code

Let’s take a look at the source code and focus on the differences with Spring 5.0.7.release

Added configuration items allowBeanDefinitionOverriding to control whether to allow BeanDefinition cover, by default is not allowed

We can configure spring.main. allow-bean-inferion-overriding =true in our configuration file to allow BeanDefinition overriding

This is a better way of doing things, and leaving the options to the developers, rather than secretly handling them yourself, has achieved what the developers want

conclusion

Spring 5.0.7.release (Spring Boot 2.0.3.release) supports @Configuration + @Bean and @Component on the same class

Info level logging will be prompted on startup, and @Configuration + @Bean qualified BeanDefinitions will be overwritten by @Component qualified BeanDefinitions

Perhaps the Spring team realized that the above processing was inappropriate and optimized it in Spring 5.1.2.release

Added configuration items: allowBeanDefinitionOverriding, the initiative to the developers, to decide whether to allow coverage by the developer

supplement

About allowBeanDefinitionOverriding, speaking in front of the wrong, later go to under the double source, supplement as below

Spring 1.2 introduced DefaultListableBeanFactory when I was a private Boolean allowBeanDefinitionOverriding = true; By default, BeanDefinition is allowed to override

Spring 4.1.2 introduced isAllowBeanDefinitionOverriding () method

Spring always allows BeanDefinition to be overridden by default, Spring Boot, Before Spring Boot 2.1.0 does not cover Spring allowBeanDefinitionOverriding default values, is still allowed to BeanDefinition coverage

In the Spring the Boot 2.1.0 SpringApplication defines the private property: allowBeanDefinitionOverriding

Did not show the specified value, then the default value is false, in the Spring after the Boot startup process, will use this value to cover off in the Spring allowBeanDefinitionOverriding default values

About allowBeanDefinitionOverriding, I think we should have clear