Let's start with the @SpringBootApplication annotation of the main program class.
First, we click into @SpringBootApplication:
we see that it is composed of four meta annotations @Target, @Retention, @Documented, and @Inherited and @SpringBootConfiguration, @EnableAutoConfiguration, @ComponentScan ( ) An annotation composed of three annotations;
we don't need to say more about meta annotations. Next, I will explain the three annotations @SpringBootConfiguration, @EnableAutoConfiguration, and @ComponentScan.
Let's first talk about two simple annotations @SpringBootConfiguration and @ComponentScan annotations, and finally talk about the core and most troublesome annotation @EnableAutoConfiguration annotation.
一.@SpringBootConfiguration
We click into @SpringBootConfiguration:
we found that it is composed of meta-annotations and @Configuration, that is, @Configuration annotations. What is @Configuration? It means that it is currently a configuration class.
In other words, our MainApplication main program class is also a configuration class, but it is a core configuration class.
二.@ComponentScan
@ComponentScan we all know that it is a package scanning annotation, which specifies what to scan.
三.@EnableAutoConfiguration
Here comes, the most important thing is finally here.
Closer to home, we click into the @EnableAutoConfiguration annotation: we
found that it is composed of 4 meta annotations and @AutoConfigurationPackage, @Import({AutoConfigurationImportSelector.class}) annotations.
Let's talk about the @AutoConfigurationPackage annotation first, and then the role of the component imported by @Import({AutoConfigurationImportSelector.class}).
1.@AutoConfigurationPackage
We click into the @AutoConfigurationPackage annotation: we
find that it is actually an @Import annotation. What is the imported Registrar? Let's click in and take a look:
I found that it has two methods. In fact, Registrar is to register components in batches in the container. Because it is too troublesome to import one by one with import, so write a piece of code to register
in batches; we put a breakpoint on the first method, you can see Which components does it register:
This method has two parameters, as follows:
AnnotationMetadata is the source information of the annotation, and the annotation refers to @AutoConfigurationPackage. The source information of the annotation indicates where the annotation is marked and what each attribute value of it is , This annotation is the annotation in @SpringBootApplication, @SpringBootApplication is marked on the MainApplication main program class, so it is actually marked on the MainApplication main program class.
We can open the metadata to view its information during debugging: we
find that it is indeed on the main program class, and then we continue to talk about this method. This method here has a new PackageImports:
equivalent to getting our annotation source information to get ours The package name, we can let it calculate what the package name we get:
you can see that the package path where the MainApplication main program class is calculated.
Let's talk about that method. After it gets our package path, it gets the package name of the main program class, then encapsulates the package name into an array, and then registers it for us in the container.
In other words, our Registrar is equivalent to registering all the components under a certain package into the container in batches.
@AutoConfigurationPackage small summary:
- Use Registrar to import a series of components into the container
- Import all the components in the package where the MainApplication main program class is located
2.@Import({AutoConfigurationImportSelector.class})
Use the selector to import some components into the container in batches.
We click into the AutoConfigurationImportSelector:
the array returned by our selectImports method specifies which components to import into the container, and the getAutoConfigurationEntry method is called in the selectImports method, so we now
Let’s study the getAutoConfigurationEntry method, enter the getAutoConfigurationEntry method, and put a breakpoint on the body of the getAutoConfigurationEntry method: debug run, when we run one by one to get the configuration, we can see that there are 130 configurations:
click on the configurations and you will find 130 full class names. Explain that all the 130 components specified by the full class name are to be imported into our container:
then how do we know that these 130 are like this? We give a breakpoint to the getCandidateConfigurations method and re-debug:
enter the method and find that it actually uses these Spring factory loaders to load some things:
click into SpringFactoriesLoader.loadFactoryNames:
then click into (List)loadSpringFactories(classLoaderToUse ):
Finally use this method to load all the components for us, then where do we load all the components from?
We put a breakpoint on the loadSpringFactories method body and re-debug:
you can see that it loads a resource file here, the location is: META-INF/spring.factories
In other words, all files in the META-INF/spring.factories location in our current system are scanned by default;
now we look at the META-INF under the spring-boot-autoconfigure-2.4.1.jar package:
Found that it has a spring.factories file:
check the content of the file, there is a configuration item, org.springframework.boot.autoconfigure.EnableAutoConfiguration:
from line 22 to line 151, a full 130 lines of content:
this is our 130 components that need to be loaded , They are all here, and they are all hard-coded in this configuration file, which means that all the configuration classes loaded in the container will be loaded when spring-boot is started.
But is the reality like this? Is it really necessary to load all 130 components into the container?
Actually not, our SpringBoot has the function of enabling automatic configuration items on demand.
Although all the automatic configurations of our 130 scenes are loaded by default when they are started. xxxxAutoConfiguration, but will eventually be configured on demand, according to the conditional assembly rules (@Conditional).
For example, we click into AopAutoConfiguration:
In this class, we did not import the Advice class in org.aspectj.weaver, so its internal class AspectJAutoProxyingConfiguratio will not take effect: