preface

If we want to use a traditional Spring application, we need to configure a large number of XML files to launch, and as the project gets bigger and bigger, the configuration files become more and more cumbersome, which to some extent also brings difficulties to developers, so SpringBoot came into being.

What is SpringBoot?

In October 2012, a guy named Mike Youngstrom created a feature request in Spring Jira to support containerless Web application architectures in the Spring Framework, It is proposed to configure Web container services within the main container boot Spring container. This incident should be said to have played a role in the birth of SpringBoot.

SpringBoot was created to simplify the tedious XML configuration in Spring. The essence of SpringBoot is still the Spring framework. With SpringBoot, you can start a service without using any XML configuration. This allows us to build an application more quickly when using the microservices architecture.

SpringBoot has the following features:

  • Create a separate Spring application.
  • Directly embedded in Tomcat, Jetty, or Undertow (no need to deploy a WAR file).
  • Fixed configurations are provided to simplify configuration.
  • Automatically configure Spring and third-party libraries whenever possible.
  • Provides production-ready features such as metrics, health checks, and externalized configurations.
  • No code generation is required and no XML configuration is required.

Two of the most important of these SpringBoot features are convention over configuration and auto-assembly.

Convention over Configuration

The SpringBoot convention configuration is mainly reflected in the following aspects:

  • The Maven project configuration files are stored in the Resources directory.
  • The default compiled files for maven projects are placed in the target directory.
  • Maven projects are packaged in JAR format by default.
  • The default configuration file is application.yml or application.yaml or application.properties.
  • The configuration is activated by default through the configuration file spring.profiles.active.

Automatically.

Automatic assembly is the core of SpringBoot, how to achieve automatic assembly? Let’s take a look at SpringBoot’s autoloading mechanism as to why we can implement autoloading simply by introducing a starter dependency.

Compared to traditional Spring applications, we only need to introduce a @SpringBootApplication annotation to build a SpringBoot application.

Let’s start with this annotation from SpringBoot and see what it does for us.

Needless to say, the first four annotations are necessary to define an annotation. The key is the last three annotations: @SpringBootConfiguration, @EnableAutoConfiguration, and @ComponentScan. This means that instead of using the @SpringBootApplication composite annotation, we can start a SpringBoot application using the bottom three annotations.

@ SpringBootConfiguration annotations

This annotation, if you click on it, is actually an @Configuration annotation. This annotation should be familiar to you, but it is added to allow the current class to be managed as a Configuration class by Spring’s IOC container, because as we said earlier, SpringBoot is essentially Spring, so the @Configuration annotation that originally belongs to Spring can also be applied directly to SpringBoot.

@ ComponentScan annotations

This is a familiar annotation used to define Spring’s scan path, which is equivalent to configuring context: Component-scan in an XML file. If the scan path is not configured, By default Spring will scan for all classes annotated @Component, @Service, @Controller, etc. in the current class package and its subpackages.

@EnableAutoConfiguration

This annotation is the key to the autoloassembly, and when you click on it, it is a composite annotation made up of the @AutoConfigurationPackage and the @import annotation.

The @enablexxx annotation is not new to SpringBoot either. It has been around since Spring 3.1, such as the @enablesCheduling annotation to enable scheduled tasks.

@ Import annotations

This is a key note, so let’s use an example to illustrate it.

Define a normal class, TestImport, without any comments. We know that the class will not be scanned by Spring at this point, i.e. cannot be injected directly into the class:

public class TestImport {
}
Copy the code

What if, in real development, you define a class that, even with annotations, is not guaranteed to be scanned by Spring?

In this case, we can define another class, MyConfiguration, which can be scanned by Spring, and Import TestImport with the @import annotation. In this case, we can inject TestImport directly:

@Configuration
@Import(TestImport.class)
public class MyConfiguration {
}
Copy the code

So here’s the @ Import annotations is to Import a class AutoConfigurationImportSelector, next we need to analyze this class.

AutoConfigurationImportSelector class

After entering the class, there is a way, this method is easy to understand, the first is to look at AnnotationMetadata meta information (annotations), is there any data, no means no import returns an empty array directly, otherwise, they call getAutoConfigurationEntry method:

Enter the getAutoConfigurationEntry method:

This method is by calling getCandidateConfigurations to get candidate Bean, and save it as a collection, after go to finally, check after a series of operations, is encapsulated into AutoConfigurationEntry object to return.

Continue to enter the getCandidateConfigurations method, by this time you almost see the dawn:

There’s no need to click on it again, just look at the error message, The loadFactoryNames method goes to the meta-INF/Spring. factories file to get the class we need to import based on the fully qualified class name of EnableAutoConfiguration. While EnableAutoConfiguration class’s fully qualified class called org. Springframework. Boot. Autoconfigure. EnableAutoConfiguration, so let’s open this file to look at:

When we start the SpringBoot project, SpringBoot scans the meta-INF/Spring. factories files under all jars and reads them according to the key values. Finally, after some column operations such as de-weighting, we get the classes that need to be auto-assembled.

Note that: The spring.factories file in the image above is under the spring-boot-Autoconfigure package, which records almost all the auto-assembly classes required in the officially supplied Stater. So not every official starter will have a Spring. factories file under it.

Talk about the SPI mechanism

The idea of reading configuration files in the spring.Factories configuration file via the SpringFactoriesLoader is an SPI idea. So what is SPI?

SPI, Service Provider Interface. That is, the interface service provider. That is, we should program for the interface (abstraction), not the concrete implementation, so that we don’t have to change the code if we need to switch to another implementation of the current interface.

In Java, the database driver uses SPI technology, and every time we just need to introduce the database driver, it gets loaded because of SPI technology.

Open the DriverManager class and initialize the driver as follows:

Enter the ServiceLoader method and find that it defines a variable internally:

private static final String PREFIX = "META-INF/services/";
Copy the code

This variable is useful when loading the Driver: java.sql.Driver

Java.sql. Driver: java.sql.Driver: java.sql.Driver: java.sql.Driver: java.sql.Driver: java.sql.Driver: java.sql.Driver: java.sql.Driver: java.sql.Driver: java.sql.Driver

@ AutoConfigurationPackage annotations

If you click on this annotation, you’ll see that it ends up being an @import annotation:

This time it import a AutoConfigurationPackages inner class the Registrar, This class reads the scan path we configured in the outermost @SpringBootApplication annotation (if not configured, it defaults to the current package), and then adds all the classes below the scan path to the array.

Hand write a Stater component

Now that you know how autoloader works, you can start writing your own starter.

Naming rule for the starter component

{name}-spring-boot-starter {name}-spring-boot-starter {name}-spring-boot-starter Then name it spring-boot-starter-{name} ‘.

Of course, this is just a suggestion, and it’s ok if you don’t follow this rule, but for better identification, it’s recommended to follow this rule.

Write a starter

Write a very simple component that does only one thing: fastJSON serialization.

  • Create a SpringBoot application, Lonelywolf-spring-boot-starter.

  • Modify the POM file and add fastJSON dependencies (omitting some properties).

    Org. Springframework. Boot spring – the boot – starter – parent 2.4.0

    Com. Lonely. Wolf. Note lonelyWolf – spring – the boot – starter 1.0.0 – the SNAPSHOT

    org.springframework.boot spring-boot-starter

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.72</version>
    </dependency>
    Copy the code
  • Create a new serialization class JsonSerial to implement fastJSON serialization.

    public class JsonSerial { public String serial(T t){ return JSONObject.toJSONString(t); }}

  • Create a new autoassembly class, MyAutoConfiguration, to generate JsonSerial.

    @Configuration public class MyAutoConfiguration {

    @Bean
    public JsonSerial jsonSerial(){
        return new JsonSerial();
    }
    Copy the code

    }

  • When you’re done, make it into a JAR package, and then introduce dependencies in another SpringBoot:

    Com. Lonely. Wolf. Note lonelyWolf – spring – the boot – starter 1.0.0 – the SNAPSHOT

  • Injecting the JsonSerial object directly into the SpringBoot application will prompt you that the object cannot be found:

This is because the MyAutoConfiguration class is in the external JAR and is not scanned. So we need to import the external configuration class as well.

  • Create a meta-INF /spring.factories file in the resources directory and add the following configuration:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=

    com.lonely.wolf.note.MyAutoConfiguration

SpringBoot then manages MyAutoConfiguration to get the JsonSerial object, which can be injected directly for use.

conclusion

In this paper, from why there is SpringBoot, and where SpringBoot is convenient to start, step by step analysis of the principle of automatic assembly of SpringBoot, and finally handwritten a simple start component, Through actual combat to understand the SpringBoot automatic assembly mechanism.