SpringBoot's automatic assembly principle - it's really as simple as you think~

Posted by Grimloch on Sun, 23 Jan 2022 10:57:21 +0100

πŸ“‘ Content of this article: SpringBoot two brush automatic assembly principle - in fact, it is really as simple as you think~

πŸ“˜ Article column: Principle and project development of SpringBoot microservice

🎬 Last updated: January 22, 2022 SpringBoot two brush automatic assembly principle - in fact, it's really as simple as you think~

πŸ™Š Personal profile: a Junior Program ape who is studying in a two-year college. As a summary blogger of personal experience, he may be lazy sometimes, but he will stick to it. If you like blog very much, it is suggested to look at the following line ~ (crazy hint QwQ)

πŸŒ‡ give the thumbs-up πŸ‘ Collection ⭐ Leaving a message. πŸ“ One button three times love program ape, start from you and me

πŸš€ Understanding and in-depth understanding of SpringBoot automatic assembly principle πŸš€

πŸ’– Write in front πŸ’–

On the first day of the second brush SpringBoot, it was the same as before. It disgusted me at the beginning of the first day. I ate the automatic assembly principle of the day. Hum, I didn't see it for a day. It's like three autumn days. Children of the automatic assembly principle ~ accept their fate!!! What Xiao Fu sorted out for you today is the corresponding knowledge understanding of the principle of SpringBoot automatic assembly, as well as in-depth, how to quickly understand and deal with the ancestral question of this interview. This article is absolutely enough! Believe in yourself, this article is absolutely easy to understand. When you meet again, you will have a wonderful pen at your fingertips.

🎁 1. Convenience brought by SpringBoot automatic assembly

Everyone has studied the SSM framework. The most intuitive feeling we get is that the configuration file is too cumbersome and complex. If there is a slight inadvertent configuration error, your project will not run. This is obviously a headache, but after learning SpringBoot, you will understand that the Convention is greater than the configuration, Just simply configure SpringBoot, your project will run as you like the project integrated by SSM framework, and you can configure more dependent functions you want to configure on this basis. How can SpringBoot build a project as large and complex as before in a few simple steps? This has to mention the principle of automatic assembly, which is the benefits and convenience it brings~

matters needing attention:

  • This article's understanding of the principle of SpringBoot automatic assembly is based on the understanding of the latest version of SpringBoot-2.6.3. Some source codes may be different from some brothers and sisters, so if there is something wrong, I hope you can point out to me and I will actively correct it! Thanks for reading~

🎠 2. Automatic assembly principle of SpringBoot

When you learn how to use SpringBoot to quickly build a small project and write it on your resume as a project experience (subsequent bloggers will quickly build a ~), the HR of the interview is likely to ask you some simple questions about SpringBoot, so the principle of SpringBoot automatic assembly can be regarded as the ancestor of SpringBoot interview questions, Now let's take a look at how to master this troublesome principle of automatic assembly!

This paper will analyze the automatic assembly principle of SpringBoot from the following two aspects:

  • The first part interprets POM The XML file SpringBoot may automatically assemble those dependencies into the IOC container
  • The second part is to analyze the annotations on the main startup class of SpringBoot program to understand how SpringBoot automatically assembles the written configuration file.

🍨 1. POM. In SpringBoot program Interpretation of XML file

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.6.3</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.alascanfu</groupId>
   <artifactId>hello-springboot</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>hello-springboot</name>
   <description>Demo project for Spring Boot</description>
   <properties>
      <java.version>1.8</java.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

</project>

Step 1: after getting the source code

We can first look at the composition of the source code and analyze the source code and POM in Spring's Maven project What are the similarities and differences between XML?

Note: in IDEA, we can use Ctrl + left mouse button and click the corresponding class to enter its source code for interpretation.

Let's now truncate the analysis:

build tag

<build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

This is completely different from the build we previously configured in Spring (we previously configured the interception of Maven packaged resources in the build, those that need to be packaged and those that do not), and the label of this is that this is obviously a plug-in. You can see from the name that this is a small plug-in that Maven project is responsible for packaging the SpringBoot program. Go and see the next paragraph~

parent tag

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.6.3</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

This is the warehouse address of the parent Maven project. We Ctrl + left click spring boot starter parent to see what the warehouse configuration file has configured for us?

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.6.3</version>
  </parent>

What comes into view is still a parent project dependency. Then go in and have a look!

<properties>
    <activemq.version>5.16.3</activemq.version>
    <antlr2.version>2.7.7</antlr2.version>
    <appengine-sdk.version>1.9.93</appengine-sdk.version>
    <artemis.version>2.19.0</artemis.version>
    <aspectj.version>1.9.7</aspectj.version>
    ...
</properties>

You will magically find that many dependent version numbers are configured through properties, such as the activemq message queue aspecj AOP related, etc. here... You almost understand that many and many dependencies are configured in spring boot dependencies, and their dependent versions have been configured, If we need to import lower or higher versions of dependencies, we just need to modify the version number according to the version here~

Now that we know the relevant configurations, let's go back and have a look. Did the previous spring boot starter parent configure anything else for us?

<build>
    <resources>
      <resource>
        <directory>${basedir}/src/main/resources</directory>
        <filtering>true</filtering>
        <includes>
          <include>**/application*.yml</include>
          <include>**/application*.yaml</include>
          <include>**/application*.properties</include>
        </includes>
      </resource>
      <resource>
        <directory>${basedir}/src/main/resources</directory>
        <excludes>
          <exclude>**/application*.yml</exclude>
          <exclude>**/application*.yaml</exclude>
          <exclude>**/application*.properties</exclude>
        </excludes>
      </resource>
    </resources>

Do you look familiar??? This is the POM in the Maven project with Spring The configuration of XML files is almost the same. Configure the packaged output resources and do not intercept yml, yaml, properties and other files.

It's almost here, but careful friends will find that many configuration files will pop up in spring boot dependencies. Next, let's go back to the POM in our spring boot program XML file

      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

After we configure this, you will have the answer in your mind. Run to spring boot dependencies to see if the corresponding dependencies are popular? If you don't get popular, you can apply for your inner thoughts. The answer is yes! As you can see:

He's the only one who's not popular. What does that mean? It means that it has been automatically assembled into our IOC container and can be started and used normally. This is the implementation of POM The first part is almost like this. Of course, we also need to know why importing this will be automatically assembled to simple operation? Light import dependency can't make SpringBoot run seriously. This is just to understand the concept of automatic assembly first.

🍨 2. @ SpringBootApplication understand the principle of automatic assembly

Open the main startup class of our SpringBoot project: you will find that the main startup class code is only three lines:

@SpringBootApplication
public class HelloSpringbootApplication {
	public static void main(String[] args) {
		SpringApplication.run(HelloSpringbootApplication.class, args);
	}
}

If the @ SpringBootApplication line is deleted, it will not start normally. Let's learn about the specific functions of the @ SpringBootApplication annotation~

@The annotation analysis of SpringBootApplication is probably based on the above Xmind diagram. Because Xiaofu's Xmind has not been cracked yet, there is a bit of watermark to wait for~

πŸ₯š1,@SpringBootApplication

Start profiling @ SpringBootApplication

Ctrl + left click @ SpringBootApplication. Let's go in and see what's written in this thing~

In addition to the four native annotations, these are the four annotations that come into view.

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

@SpringBootApplication overview

  • This is a composite annotation, which is composed of three important annotations @ SpringBootConfiguration, @ EnableAutoConfiguration and @ ComponentScan.
  • At present, I don't know what he can do, but it is certain that it is the main program startup annotation of the SpringBoot program.

Next, what's the use of summarizing this @ SpringBootApplication annotation~

πŸ₯š2,@SpringBootConfiguration

@Configuration
@Indexed
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

In addition to the four primary annotations, these two children are the ones who come into sight!

**The first note, do you look familiar? Do you look familiar** This is a pure Spring annotation, an annotation injected into the IOC container as a configuration component.

@Configuration is a @ Component component. So I won't go into detail.

The second annotation @ Indexed should be unknown to many people. After all, this is a new product of spring 5. In fact, Xiaofu doesn't know much about it, but after consulting, we know that it is a component used to add indexes to pattern annotations to improve startup performance.

So now @ SpringBootConfiguration knows that @ SpringBootApplication is automatically injected into the IOC container as a Spring configuration.

πŸ₯š3,@ComponentScan

First analyze this simple annotation: you only need this annotation to scan all the annotated programs under the package where the current SpringBoot program startup class is located. As for why it is under the package of the same level directory, this is also reflected in the source code. I won't show you here.

✨ 4. @ enableautoconfiguration (key!!!) ✨

Since we all know that the above two annotations do not actually inject specific dependencies into the startup, it must be the most important thing for SpringBoot to realize automatic assembly~

@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

@EnableAutoConfiguration:

  • There is no doubt that this is also a composite annotation: it consists of @ AutoConfigurationPackage and @ Import({AutoConfigurationImportSelector.class}).
  • What's the use of it? So far, through this source code, we can only see that this annotation will autoconfigurationimportselector Class is a class called auto assembly import selector, which is injected into the IOC container. What's the use of this class? Let's talk later.
  • So what does @ AutoConfigurationPackage do? I don't know. Just go in.
πŸŽ—1,@AutoConfigurationPackage
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};
}
  • From the source code, we know that the annotation does one thing, that is, register Class is injected into the IOC container, so we must understand what this class called registration has done!!!
  • The magic thing is that after you click in, the registration class is registrar Class is actually autoconfigurationpackages Java static inner class.
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }
		//Import the data in the package of @ ComponentScan for automatic registration
        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
        }
		//Determine the correctness of data import
        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
        }
    }
  • This registration class is used to read the metadata annotation metadata in the package read from @ ComponentScan for automatic registration.

The summary is @ AutoConfigurationPackage. This annotation is used to read the metadata of Java programs registered through annotation in @ ComponentScan for automatic registration

πŸŽ—2,AutoConfigurationImportSelector.class
public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

This is the first method in this class. It is used to select imported data and import according to metadata annotationMetadata~

  • If metadata import is not supported, an empty import is returned directly.
  • Conversely, call getAutoConfigurationEntry in the class to get this method of the auto assembly entity

One of these methods calls the list < string > getcandidate configurations (annotationmetadata, annotationattributes) method

Call list < string > configurations = this getCandidateConfigurations(annotationMetadata, attributes); The main purpose of this method is to obtain all candidate configurations.

getCandidateConfigurations(annotationMetadata, attributes)

Enter the source code to see what it has done?

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
    }
  • This method for obtaining candidate configurations is used to load all required configurations through the static method loadFactoryNames of the springfactoryesloader class. Where do these configurations come from?
  • One of its parameters, getSpringFactoriesLoaderFactoryClass(), returns a class that supports automatic assembly!!!
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
        return EnableAutoConfiguration.class;
    }

The loadFactoryNames method returns a map < string, list < string > > loadspringfactories (classloader, classloader)

You can see that there is an enumeration class to read / meta-inf / spring The resource path of factories. What is stored in this path?

πŸŽ‰3,/META-INF/spring.factoriesπŸŽ‰

1. This is the file that SpringBoot helps us configure automatically. Its directory is located in spring-boot-autoconfigure-2.6.3 Spring.inf in META-INF under jar factories.
2. You can find all the file auto configuration classes that SpringBoot automatically configures for us.

✨5,xxxxxAutoConfiguration✨

Important: as for whether each auto assembly class is automatically configured to be assembled into the IOC container? How could it be? It's with the POM XML file, you must understand now ~, and how does SpringBoot distinguish which are assembled and which are not assembled?

So let's look at how these automatic assembly classes are written~

Here we use our most commonly used DataSourceAutoConfiguration as an example

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@ConditionalOnMissingBean(
    type = {"io.r2dbc.spi.ConnectionFactory"}
)
@AutoConfigureBefore({SqlInitializationAutoConfiguration.class})
@EnableConfigurationProperties({DataSourceProperties.class})
@Import({DataSourcePoolMetadataProvidersConfiguration.class, InitializationSpecificCredentialsDataSourceInitializationConfiguration.class, SharedCredentialsDataSourceInitializationConfiguration.class})
public class DataSourceAutoConfiguration {
}

You can see many notes we don't know, but we can basically see the meaning of the name:

For example:

  • ConditionalOnClass: this means that these two classes must exist in the IOC container before they can be automatically assembled
  • ConditionalOnMissingBean: it means that there must be no such component type in IOC before assembly
  • Autoconfigurebeefore: represents that the assembly must be completed before SqlInitializationAutoConfiguration auto assembly
  • EnableConfigurationProperties: Java type files that support configured properties configuration files, and properties configured in yaml or properties.

If you don't understand here, you can enter datasourceproperties Class, you'll know what this thing is for

In this way, the automatic assembly principle of the whole SpringBoot will be thoroughly understood, but the run method actually started and how to start it will be discussed separately~

🧨 3. Summarize the principle of SpringBoot automatic assembly 🧨

When the SpringBoot program starts, it will find the spring boot autoconfigure.exe through the @ EnableAutoConfiguration annotation Meta-inf / spring.jar All auto configuration classes in the factories file and load them. These found auto configuration classes are named in the form of xxxAutoConfiguration. Simply understand that this is the JavaConfig automatic configuration file. Get the Properties configured in the global configuration file through the class named at the end of Properties, such as spring datasource. Url = XXXXXX is the best embodiment of the principle of automatic assembly.

πŸ’– Write it at the back πŸ’–

A little knowledge and a little algorithm every day

Over time, no regrets

The road to the future must be bright!

come on. Pay tribute to everyone on the way forward~

Topics: Java Spring Boot Back-end Interview