Note: The source code analysis corresponds to SpringBoot version 2.1.0.release

1 Review the old and learn the new

How are external configuration property values bound to XxxProperties class properties? –SpringBoot source code (5)

Review, let’s briefly review the content of the last article, the last article we analyzed the SpringBoot external configuration attribute value is how to be bound to XxxProperties class attributes on the relevant source code, now the important steps of external attribute binding summarized as follows:

  1. The first is@EnableConfigurationPropertiesannotationsimporttheEnableConfigurationPropertiesImportSelectorRear processor;
  2. EnableConfigurationPropertiesImportSelectorThe rear processor goes toSpringRegistered in the containerConfigurationPropertiesBeanRegistrarandConfigurationPropertiesBindingPostProcessorRegistrarThe twobean;
  3. Among themConfigurationPropertiesBeanRegistrartoSpringRegistered in the containerXxxPropertiesThe type ofbean;ConfigurationPropertiesBindingPostProcessorRegistrartoSpringRegistered in the containerConfigurationBeanFactoryMetadataandConfigurationPropertiesBindingPostProcessorTwo rear processors;
  4. ConfigurationBeanFactoryMetadataThe rear processor is initializingbean factoryWhen will@BeanMetadata for annotations is stored for use in subsequent external configuration of the property binding logic;
  5. ConfigurationPropertiesBindingPostProcessorThe post-processor binds the value of the external configuration property toXxxPropertiesThe logical delegate of a class attribute toConfigurationPropertiesBinderObject, and thenConfigurationPropertiesBinderThe object ultimately delegates the property binding logic toBinderObject to do.

As you can see, the important step is step 5 above.

2 the introduction

As we all know, SpringBoot comes with a variety of built-in Starter dependencies that are very easy to use and greatly ease our development efforts. With the Starter dependency, we don’t have to worry about what library the project needs. What are the groupId and artifactId of the library? There is no need to worry about whether the introduction of this version of the library will conflict with other dependencies.

For example: now that we want to develop a Web project, we can simply introduce the spring-boot-starter-Web starter dependency, regardless of which versions and which dependencies to introduce. Like before, we had to consider which dependency libraries to introduce, such as spring-Web and Spring-WebMVC dependencies; Also, consider which versions of these libraries to introduce so they don’t conflict with other libraries.

So we do not analyze the source code of SpringBoot automatic configuration today, because the relationship between starting dependence and automatic configuration is the relationship, so this first stand in the perspective of Maven project construction to macro analysis of our usual use of SpringBoot built-in Starter is how to build?

3 Maven passes dependent optional tags

Before taking a look at SpringBoot’s various Starter building principles, let’s take a look at Maven’s optional tag, because it plays a crucial role. Maven’s optional tag indicates that an optional dependency is not passable.

For example, if you have libraries A,B, and C, C depends on B, and B depends on A. Take a look at the pom.xml file for the three libraries:

/ / A of pom. The 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

	<groupId>com.ymbj</groupId>
        <artifactId>A</artifactId>
	<version>1.0-SNAPSHOT</version>

</project>
Copy the code
<? 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

	<groupId>com.ymbj</groupId>
        <artifactId>B</artifactId>
	<version>1.0-SNAPSHOT</version> <! --> <dependencies> <dependency> <groupId>com.ymbj</groupId> </artifactId> <version>1.0-SNAPSHOT</version>
	    <optional>true</optional>
        </dependency>
    </dependencies>

</project>
Copy the code
<? 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

	<groupId>com.ymbj</groupId>
        <artifactId>C</artifactId>
	<version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>com.ymbj</groupId>
            <artifactId>B</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>
Copy the code

Maven is A Maven Maven library. Maven is A Maven Maven library. Maven is A Maven Maven library.

Maven’s optional tag is set to true. Maven’s optional tag is set to true. Maven’s optional tag is set to true, and Maven’s optional tag is set to true.

Also associated with Maven’s dependencies is the exclusions tag, which means the exclusion of a child dependency of a library and is not discussed here.

How are the various Starter built into SpringBoot?

Now let’s explore how SpringBoot’s built-in Starter is built.

Remember how to analyze SpringBoot source modules and structures? Does this article analyze the relationships between modules within SpringBoot? Let’s review the internal module diagram of SpringBoot source code:

As we all know, the essence of SpringBoot Starter construction principle is automatic configuration, so it can be seen from Figure 1 that the SpringBoot source project has four modules related to Starter and its automatic configuration: Spring – the boot – starters, spring – the boot – physical – autoconfigure, spring – the boot – autoconfigure and spring – the boot – test – autoconfigure. See how to analyze SpringBoot source module and structure? This article will not be repeated here.

How does the Spring-boot-Henceforth relate to the xxx-Autoconfigure module?

So let’s take a look at the spring-Boot-Henceforth module and what does it look like?

As can be seen from Figure 2, the Spring-boot-Starters module includes various built-in SpringBoot starters: Spring-boot-starter – XXX. Because SpringBoot has too many built-in starter, we use the spring-boot-starter- Web startup dependency to explore the good.

Let’s first look at the internal structure of the spring-boot-starter-Web module:

You can see that in the spring-boot-starter-web module there’s just.flattened- pop.xml and pop.xml files, and no code! A bit of a surprise. We all know that if we want to use SpringBoot’s web function, we can introduce the spring-boot-starter-Web startup dependency. Now there is not a line of code in the spring-boot-starter-Web module. So how exactly is spring-boot-starter-Web built? Could it have something to do with the spring-boot-Autoconfigure auto-configuration module shown in Figure 1?

In this case, we need to look at the pom. XML file of the spring-boot-starter-Web module:

As can be seen from Figure 4, the spring-boot-starter-Web module relies on the spring-boot-starter, spring-boot-starter-Tomcat, spring-Web and spring-webMVC modules. Not relying on the spring-boot-autoconfigure auto-configuration module!

Since the spring-boot-starter-Web module is definitely related to the spring-boot-autoconfigure auto-configuration module, So the spring-boot-starter-Web module is definitely indirectly dependent on the spring-boot-autoconfigure automatic configuration module.

The spring-boot-starter module labeled “Focus” in Figure 4 is the base module that most spring-boot-starter-XXX modules rely on. It is the core starter, including auto-configuration, logging, and YAML support. Take a look at the pop. XML file for spring-boot-starter, which probably relies on the spring-boot-Autoconfigure module.

Figure 5 shows that the spring-boot-starter module relies on the spring-boot-autoconfigure module. So here we come to the conclusion: The spring-boot-starter-Web module does not have a line of code, but it indirectly relies on the spring-boot-Autoconfigure automatic configuration module through the spring-boot-starter module, so as to realize its start-dependent function.

Spring-boot-autoconfigure = spring-boot-autoconfigure = spring-boot-autoconfigure

From the red box in Figure 6, we can see that the auto-configuration function that spring-boot-starter-Web startup relies on was originally implemented by classes in the Web package of the Spring-boot-Autoconfigure module.

At this point, the build rationale for spring-boot-starter-Web startup dependencies is clear, but there’s one particularly important key we haven’t gotten to yet. This key point has to do with what Maven’s optional tag does.

Spring-boot-starter-web (spring-boot-autoconfigure); spring-boot-autoconfigure (spring-boot-autoconfigure); spring-boot-autoconfigure (Spring-boot-autoconfigure); spring-boot-autoconfigure (Spring-boot-autoconfigure);

We should be aware that some automatic configuration type work is often the result of a class exist in the classpath here to DispatcherServletAutoConfiguration this automatic configuration such as the breakthrough point to Get the point. First look at the conditions of the DispatcherServletAutoConfiguration can automatic configuration is what?

By shown in figure 7, DispatcherServletAutoConfiguration can automatic configuration is one of the conditions of @ ConditionalOnClass (DispatcherServlet. Class), Which only exist in the classpath DispatcherServlet. Class, this class so DispatcherServletAutoConfiguration automatic configuration logic related to work.

The DispatcherServlet class is in the spring-WebMVC dependency library, as shown below:

The spring-boot-autoconfigure module’s pop. XML file imports the spring-webMVC dependency.

As shown in Figure 9, the spring-boot-Autoconfigure module introduces the spring-webMVC dependency with optional set to true, which was originally an optional dependency. The spring-webMVC dependency library will only be imported into the Spring-boot-Autoconfigure module. It is not imported into the spring-boot-starter-web dependency that indirectly depends on the spring-boot-autoconfigure module.

Now, let’s seespring-boot-starter-webthepom.xmlFile dependencies:

As shown in Figure 10, the spring-boot-starter-Web startup dependency explicitly introduces the spring-WebMVC dependency library, i.e., spring-WebMVC is introduced without the optional tag, Because the DispatcherServlet class is in the spring-WebMVC library, the classpath contains the DispatcherServlet class. So DispatcherServletAutoConfiguration this automatic configuration class will take effect. Of course, other Web-related auto-configuration classes work the same way.

We can see why the spring-boot-Autoconfigure module makes the spring-webMVC dependency optional. The goal is to explicitly introduce the Spring-webMVC dependency in the Spring-boot-starter-Web startup dependency (which is decisive) so that we can develop web projects by introducing the Spring-boot-starter-Web startup dependency, So the Web-related auto-configuration classes take effect and are ready to use out of the box and this is the building principle that spring-boot-starter-Web relies on.

The aforementioned spring-boot-starter-actuator, Spring-boot-starter -test and other built-in Spring-boot-starter – XXX are built in the same way. But spring-boot-objective-actuator relies on spring-boot-objective-actuator autoconfigure, Spring-boot-starter-test relies on the spring-boot-test-autoconfigure module.

The pop. XML file of spring-boot-exoskeleton-autoconfigure introduces more than 20 optional dependencies. Why does spring-boot-starter-actuator only introduce micrometer-core?

5 Customize a Starter based on the SpringBoot package structure

The previous analysis of SpringBoot built-in Starter construction principle, theory and practice, so if you can hands-on practice custom Starter that is better.

The following provides a simple Demo of a custom Starter, this Demo completely imitate the internal package structure of SpringBoot built-in Starter to write, for further understanding of the various SpringBoot built-in Starter construction principle is very helpful.

Below is the github address of this Demo, recommended to interested partners. Customize the Starter by emulating the internal structure of SpringBoot. In addition, how to customize a Starter, can refer to Mybatis spring-boot-starter is how to write.

6 summary

Well, the analysis of the construction principle of various Starter built by SpringBoot is over here. Now the key points are summarized:

  1. spring-boot-starter-xxxStarting dependencies don’t have a line of code, but are directly or indirectly dependentxxx-autoconfigureModule, andxxx-autoconfigureThe module takes overspring-boot-starter-xxxStarting depends on the implementation of automatic configuration;
  2. xxx-autoconfigureThe auto-configuration module introduces optional dependencies that are not passed tospring-boot-starter-xxxStarting dependency, this is built by starting dependencyThe key point;
  3. spring-boot-starter-xxxStart relying onexplicitIntroduced some optional dependencies that work with auto-configuration;
  4. After the preparation of the previous three steps, our project simply introduced a startup dependency and was ready to use it out of the box instead of manually creating somebeanAnd so on.

Due to the author’s limited level, if there are mistakes in the article, please point out, thank you.

1. Maven dependency transitivity is thoroughly understood