Super detailed SpringBoot automatic configuration principle analysis (part 1)

@ SpringBootApplication annotations

You must be very familiar with the details of this annotation. Take a good look at this note again.

We click on the annotation and see that it consists of multiple annotations. This kind of annotating is really a headache to watch

  • @ComponentScan, without further elaboration, is an automatically scanned annotation. It should all be familiar

We’ll focus on the two SpringBoot annotations, @SpringBootConfiguration and @EnableAutoConfiguration

We click on the @SpringBootConfiguration annotation and see that it doesn’t have much in it, just a wrapper around the @Configuration annotation.

In short, it’s just an @Configuration annotation.

That leaves the @enableAutoConfiguration annotation, which is extremely deep

After clicking on the annotation, we see the @AutoConfigurationPackage and @import annotations

  • @AutoConfigurationPackageThere’s nothing to say about annotations, which, as their name suggests, are used to auto-configure packages. That is, the class that makes the annotation markPackage and all subpackages belowAll the components inside are scanned into the Spring container.
  • @ImportAnnotations import oneAutoConfigurationImportSelectorClass, let’s click in and see what this class does.

We see that this class implements a number of interfaces, so let’s look at the DeferredImportSelector interface, click on that interface, and see that it inherits the ImportSelector interface. And if I go a little further in, I see the ImportSelector interface that has a selectImports method, and that’s it.

We went back to AutoConfigurationImportSelector classes, see how selectImports this method be rewritten.

First, if determines whether the automatic configuration function is disabled. If disabled, return a constant, which is an empty array. There is no way to inject beans.

Downwards see again call a getAutoConfigurationEntry method, let’s take a look at what happened this way.

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    // Check whether autoload is allowed. If not, return empty set. Default: true
	if(! isEnabled(annotationMetadata)) {return EMPTY_ENTRY;
	}
    // The getAttributes method obtains the excludeName, exclusion, and other attributes in the @enableAutoConfiguration annotation.
	AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // == Another key method == This method is used to get the auto-configuration classes associated with the Spring. factories file EnableAutoConfiguration
	List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // Remove duplicate configuration classes
	configurations = removeDuplicates(configurations);
    // Get the auto-configuration class to exclude
	Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    // Check the configuration classes to be excluded
	checkExcludedClasses(configurations, exclusions);
    // Remove all configuration classes to be excluded
	configurations.removeAll(exclusions);
    // Filter operations to avoid memory waste
	configurations = getConfigurationClassFilter().filter(configurations);
    // Notify the listener to record the qualified auto-configuration classes
	fireAutoConfigurationImportEvents(configurations, exclusions);
    // Encapsulate the qualified and excluded auto-configuration classes into an AutoConfigurationEntry object and return it
	return new AutoConfigurationEntry(configurations, exclusions);
}
Copy the code

The AutoConfigurationEntry method is mainly used to obtain qualified auto-configuration classes and to avoid loading unnecessary auto-configuration classes (which would waste memory).

We take a look at to get all the automatic configuration class getCandidateConfigurations method.

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
    getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "+ "are using a custom packaging, make sure that file is correct.");
    return configurations;
}
Copy the code

See the familiar loadFactoryNames() method again; Let’s put the camera in loadFactoryNames and review how SpringBoot loads the value of the specified key from meta-INF/Spring.Factories.

public static List<String> loadFactoryNames(Class<? > factoryType,@Nullable ClassLoader classLoader) {
    // Get the fully qualified name of the retrieval class
    String factoryTypeName = factoryType.getName();
    // Load and retrieve the spring.factories set and return the empty set
    return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
Copy the code

Debug, look from the meta-inf/spring. The factories in the loading of a class key, as shown in the figure below: org. Springframework. Boot. Autoconfigure. EnableAutoConfiguration

Back to selectImports () method, the debug, skip a List < String > configurations = getCandidateConfigurations (annotationMetadata, attributes); Look at the configurations

There are more than a hundred. Where are all these classes? “Meta-inf /spring.factories” under the spring-boot-autoconfigure project We can see org. Springframework. Boot. Autoconfigure. EnableAutoConfiguration defines a lot of.

Set Exclusions = getExclusions(annotationMetadata, Attributes); Method that excludes autowiring classes that are excluded from the @SpringBootApplication annotation on the main class. For example, if we exclude our custom starter autowiring class from this annotation, @ SpringBootApplication (exclude = {com. Demo. Starter. Config. DemoConfig. Class}) (of course, can also use excludeName excluded), Configurations. RemoveAll (Exclusions); Method will remove our com. Demo. Starter. Config. DemoConfig. Class.

configurations = filter(configurations, autoConfigurationMetadata); This line of code will filter out classes that do not need to be assembled. There is a lot of logic to filtering, such as the @conditionxxx annotation we all use. As shown below.

ConditionalOnBean: ConditionalOnBean in the container ConditionalOnExpression: ConditionalOnJava: ConditionalOnJava: ConditionalOnJava: ConditionalOnJava: ConditionalOnJava: ConditionalOnJava: ConditionalOnJava: ConditionalOnJava @ ConditionalOnJndi: in the presence of JNDI to find the location specified @ ConditionalOnMissingBean: when the container is not specified under the condition of Bean @ ConditionalOnMissingClass: when there is no specified class under the class path @ ConditionalOnNotWebApplication: the current project is not a Web project @ ConditionalOnProperty: the configuration file to specify properties for the specified value @ ConditionalOnResource: if there is a specified resource classpath @ ConditionalOnSingleCandidate: when specifying the Bean in the container is only one, or even though there are multiple specify preferred Bean @ ConditionalOnWebApplication: the current project is under the condition of the Web project

The above auto-configuration class, which does not satisfy @conditionxxx, would not be injected into an IoC container

The auto-configuration class that meets @conditionxxx is then imported into the IoC container

In addition to these conditional comments, we have a few more comments to make

This class find EnableConfigurationProperties annotations, point into it.

When we click in we see a prefix (spring.mvc) and a lot of properties.

It’s not hard to guess that these properties are the corresponding configurations that we can customize in the application.yaml configuration file.

Let’s seeConfigurationPropertiesThis annotation

This annotation matches the configuration item in our configuration file with the prefix in its prefix parameter.

If a match is found, the configuration item in our configuration file is read into the class whose prefix matches it

And EnableConfigurationProperties annotations inject the class to our the IoC container, then we start SpringBoot when the main program is the realization of the natural operation of custom configurations.

Due to space problems, there is still a part not covered, that is, the injection of IoC container. Interested friends can go to the blog garden of the original author to have a look at this article. I will post the address here

SpringBoot startup process analysis (vi) : IoC container dependency injection


Relax your eyes

Smuggle (no

Original picture P station address

Artist’s home page:…… Uh, P station collapsed and couldn’t get up.