1. @SpringBootApplication
To talk about the auto-configuration of Spring Boot, it is important to start with the project’s starter class @SpringBootApplication
, which is the starting point of the whole Spring Boot universe. The definition of this annotation is as follows.
|
|
As can be seen, the @SpringBootApplication
annotation combines the functionality of several common annotations, of which:
- The first four are meta annotations, which we will not discuss here.
- The fifth
@SpringBootConfiguration
is a configuration class support annotation, which we won’t discuss here either. - The sixth
@EnableAutoConfiguration
is an annotation to enable auto-configuration, which is what we’re going to talk about today. - The seventh
@ComponentScan
is a package scan annotation, and it’s the reason whyBean
s in aSpring Boot
project are automatically scanned if they are in the right place.
There are only two annotations provided by Spring Boot
, @SpringBootConfiguration
and @EnableAutoConfiguration
, the others have been around for years before Spring Boot
came along.
2. @EnableAutoConfiguration
Next let’s see how @EnableAutoConfiguration
implements auto-configuration.
There are 2 core annotations on this annotation:
@AutoConfigurationPackage
: This means that it automatically scans for various third-party annotations, which are not explained here.@Import
is importing theAutoConfigurationImportSelector
configuration class, which is used to load various auto-configuration classes.
3. AutoConfigurationImportSelector
The AutoConfigurationImportSelector
class has a lot of methods, but the entry point is the process method, so we’ll start with the process method here.
|
|
As you can see from the class name, the objects related to the auto-configuration are loaded by AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector).getAutoConfigurationEntry(annotationMetadata);
is loaded.
Of course the getAutoConfigurationEntry
method here is actually the method provided by the current class, so let’s take a look at that method:
|
|
The naming of the methods in the source code here is well done, and you can basically see the name and know what it means.
3.1 isEnabled
The isEnabled method is called first to determine if the auto-configuration is enabled or not. This is mainly because even after we have introduced spring-boot-starter-xxx into the project, we can turn off all automation by configuring spring.boot.enableautoconfiguration=false
in application.properties. configuration.
The relevant source code is as follows:
3.2 getCandidateConfigurations
Next, call the getCandidateConfigurations
method to get all the candidate auto-configuration classes, which come from two main sources:
- all the auto-configuration classes defined in
claspath\:META-INF/spring.factories
, which is source one. - the auto-configuration classes that come with
Spring Boot
.Spring Boot
comes with its own auto-configuration classes located inspring-boot-autoconfigure-3.0.6.jar!\META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports
file.
The relevant source code is as follows:
|
|
The full path to the auto-configuration classes loaded here are stored in the configurations
object, which has two places to get them from:
- call the
SpringFactoriesLoader.loadFactoryNames
method to get it, which is relatively simple and essentially loads theMETA-INF/spring.facts
file, which defines the full paths to a large number of auto-configuration classes. - call the
ImportCandidates.load
method to load, this is to loadspring-boot-autoconfigure-3.0.6.jar!\META-INF\spring\org.springframework.boot.Autoconfigure.AutoConfiguration.imports
file with the auto-configuration classes.
If no auto-configuration class is loaded in either of these places, then an exception is thrown.
3.3 removeDuplicates
The removeDuplicates
method removes duplicate classes from a candidate auto-configuration class. The source code is as follows:
3.4 getExclusions
The getExclusions
method indicates that all excluded auto-configuration classes need to be fetched, and that these excluded auto-configuration classes can be fetched from three places:
- the
exclude
attribute of the current annotation. - the
excludeName
attribute of the current annotation. - the
spring.autoconfigure.exclude
property in theapplication.properties
configuration file.
Take a look at the source code:
|
|
3.5 checkExcludedClasses
This method checks for all excluded automation classes. Since the automation classes in Spring Boot
are customizable and do not need to uniformly implement an interface or uniformly inherit from a class, the compilation will not check if you write an excluded class incorrectly, like the following:
Since HelloController
is not an auto-configuration class, writing the project this way will throw an exception when it starts, as follows:
Where does this exception come from? It actually comes from the checkExcludedClasses
method, which we look at:
|
|
You can see that in the checkExcludedClasses
method, all excluded auto-configuration classes that are located under the current class path but are not included in configurations
are first found, and since the ones in configurations
are all the auto-configuration classes, those that do not exist in configurations
are faulty, and are not auto-configuration classes. These faulty classes are collected and stored in the invalidExcludes
variable, and then subjected to additional processing.
The extra handling is to throw an exception in the handleInvalidExcludes
method, which is where the previous exception came from.
3.6 removeAll
This method removes the excluded auto-configuration classes from configurations
. configurations
itself is a List
set, and exclusions
is a Set
set, so it can be removed directly here.
3.7 filter
Now we have loaded all the auto-configuration classes, but not all of them will take effect, depending on whether your project uses specific dependencies.
For example, the auto-configuration loaded now includes RedisAutoConfiguration
, which automatically configures Redis, but since my project does not use Redis, this auto-configuration class will not take effect. This process is done by getConfigurationClassFilter().filter(configurations);
.
Let’s start with a bit of preparatory knowledge:
Since we have a particularly large number of auto-configuration classes in our project, each one will depend on other classes, and the auto-configuration class will only take effect when the other class exists, a bunch of dependencies on each other that exist in the spring-boot-autoconfigure-3.0.6.jar!/META-INF/spring- autoconfigure-metadata.properties
file, and I’ll give you a random example of the configuration in that file:
org.springframework.boot.autoconfigure.amqp.RabbitAnnotationDrivenConfiguration.ConditionalOnClass=org.springframework.amqp. rabbit.annotation.EnableRabbit
means that for the RabbitAnnotationDrivenConfiguration class to take effect, one requirement is the presence of org.springframework.amqp.rabbit. annotation.EnableRabbit
.
Let’s take a look at the annotations for the RabbitAnnotationDrivenConfiguration
class:
This class corresponds to the contents of the configuration file.
Once this preparatory knowledge is understood, the rest is easy to understand.
Let’s start with the getConfigurationClassFilter
method, this is where you get all the filters, as follows:
|
|
As you can see, the filters obtained here are all of type AutoConfigurationImportFilter, and there are only three instances of this type of filter, as follows:
From the names of these three instances, you can basically see what each one does:
- OnClassCondition: This is the condition for the conditional annotation
@ConditionalOnClass
, which is used to determine whether a class exists under the current classpath. - OnWebApplicationCondition: This is the condition for the conditional annotation
ConditionalOnWebApplication
, and is used to determine whether the current system environment is a Web environment. - OnBeanCondition: This is the condition for the conditional annotation
@ConditionalOnBean
, which determines whether a bean exists on the current system.
The three AutoConfigurationImportFilter
filters obtained here are in fact the three above. The filter method is then executed as follows:
|
|
Here the three filters are iterated over and their respective match methods are called to match each of the 144 auto-configuration classes. If the conditions required by these automation classes are met, the match array will have a value of true at the index position, otherwise it will be false.
The match array is then iterated through, setting any automation classes that do not satisfy the condition to null, and finally removing these nulls.
This gives us the class we need to automate the configuration.
The last line, fireAutoConfigurationImportEvents, triggers the auto-configuration class import event.
Once these auto-configuration classes have been loaded, it is then up to the various conditional annotations to determine whether they take effect or not.
Reference:
https://segmentfault.com/a/1190000043859515