SpringBoot Source Parsing--- Introduction to the core principles of SpringBoot

Keywords: Java Spring SpringBoot Maven Apache

Overview of Spring Boot

Build Anything with Spring Boot: Spring Boot is the starting point for building all Spring-based applications. Spring Boot is designed to get you up and running as quickly as possible, with minimal upfront configuration of Spring.

Here's a quote from the website, which probably means that Spring Boot is the starting point for all Spring-based projects.Spring Boot is designed to allow you to run the Spring application as quickly as possible and to minimize your profile.

What is Spring Boot

  • It uses the concept of "Habits are better than configurations" (there are lots of configurations in your project, plus a custom configuration built in so you don't have to configure them manually) to get your project running quickly.
  • It's not a new framework, but rather a default configuration of how many frameworks are used, like Maven integrating all jar packages, Spring Boot integrating all frameworks

What are the benefits of using Spring Boot

Reviewing our previous SMM projects, the construction process is cumbersome and requires:

  • 1) Configure web.xml, load spring and spring mvc
  • 2) Configure database connections, configure log files
  • 3) Configurator reads profile and opens annotations
  • 4) Configure mapper file
  • .....

Developing a project with Spring Boot requires only a few configurations to build a Web project and IDEA to automatically generate the build

  • Focus on: simple, fast and easy to build projects; no configuration integration of mainstream development frameworks; greatly improves development and deployment efficiency.

Spring Boot HelloWorld

Import dependent spring boot dependent dependencies

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.chenhao</groupId>
    <artifactId>springboot</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>springboot</name>
    <description>Demo project for Spring Boot</description>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
        <relativePath/>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Write main program

/**
 * @SpringBootApplication To label a main program class, this is a SpringBoot application
 */
@SpringBootApplication
public class HelloWorldMainApplication {

    public static void main(String[] args) {
        //Spring Application Startup
        SpringApplication.run(HelloWorldMainApplication.class, args);
    }
}

Write Controller, Service

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello(){
        return "Hello world";
    }
}

Run main program tests

Once you have packaged it into a jar package using the maven packaging command, use the command directly:

java -jar xxx.jar

Hello World Exploration

POM File

Parent Project

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
    <relativePath/>
</parent>

Its parent project is

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.0.1.RELEASE</version>
    <relativePath>../../spring-boot-dependencies</relativePath>
</parent>

The parent project is really managing all dependent versions within the Spring Boot application: the version Arbitration Center for Spring Boot, so later imported dependencies do not require a version number by default.as follows

Many more version numbers are not captured

starter

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

Spring-boot-starter: spring boot scene launcher; helps import components on which the web module depends to function properly;

Spring Boot pulls out all the functional scenarios and makes them into starters one by one. All the dependencies of the related scenarios are imported into the project as long as these starters are introduced into the project.The launcher that imports any scene with what functionality you want.

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

Adding a spring-boot-starter-web dependency automatically adds Tomcat and Spring MVC dependencies

spring-boot-starter-tomcat is also introduced in spring-boot-starter-web

Main Program Class (Main Entry Class)

@SpringBootApplication
public class HelloWorldMainApplication {

    public static void main(String[] args) {
        //Spring Application Startup
        SpringApplication.run(HelloWorldMainApplication.class, args);
    }
}

@SpringBootApplication

  • The Spring Boot application is labeled on a class, indicating that this class is the main configuration class for SpringBoot, and SpringBoot should run the main method of this class to start the SpringBoot application.

The notes are defined as follows:

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

@SpringBootConfiguration

  • Configuration Class for Spring Boot
  • Label on a class to indicate that this is a configuration class for Spring Boot

The notes are defined as follows:

@Configuration
public @interface SpringBootConfiguration {}

This is actually a Configuration configuration class, meaning that the HelloWorldMainApplication will eventually be registered in the Spring container

@EnableAutoConfiguration

  • Turn on automatic configuration
  • Previously using the information Spring needs to configure, Spring Boot helps to configure automatically;
  • @EnableAutoConfiguration notifies SpringBoot to turn on auto-configuration so that it takes effect.

The notes are defined as follows:

@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

@AutoConfigurationPackage

  • Automatic configuration package annotations
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}
@Import (AutoConfiguration Packages.Registrar.class): By default, the package in which the main configuration class (@SpringBootApplication) resides and all components in its subpackages are scanned into the Spring container.as follows
@Order(Ordered.HIGHEST_PRECEDENCE)
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,
            BeanDefinitionRegistry registry) {
          //Default will scan@SpringBootApplication The package in which the labeled primary configuration class resides and all components under it
        register(registry, new PackageImport(metadata).getPackageName());
    }

    @Override
    public Set<Object> determineImports(AnnotationMetadata metadata) {
        return Collections.<Object>singleton(new PackageImport(metadata));
    }
}

@Import(EnableAutoConfigurationImportSelector.class)

EnableAutoConfiguration ImportSelector: A selector that imports which components, returns all components that need to be imported as full class names, and these components are added to the container.

 1 //EnableAutoConfigurationImportSelector The parent of: AutoConfigurationImportSelector
 2 @Override
 3 public String[] selectImports(AnnotationMetadata annotationMetadata) {
 4     if (!isEnabled(annotationMetadata)) {
 5         return NO_IMPORTS;
 6     }
 7     try {
 8         AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
 9             .loadMetadata(this.beanClassLoader);
10         AnnotationAttributes attributes = getAttributes(annotationMetadata);
11         List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
12         configurations = removeDuplicates(configurations);
13         configurations = sort(configurations, autoConfigurationMetadata);
14         Set<String> exclusions = getExclusions(annotationMetadata, attributes);
15         checkExcludedClasses(configurations, exclusions);
16         configurations.removeAll(exclusions);
17         configurations = filter(configurations, autoConfigurationMetadata);
18         fireAutoConfigurationImportEvents(configurations, exclusions);
19         return configurations.toArray(new String[configurations.size()]);
20     }
21     catch (IOException ex) {
22         throw new IllegalStateException(ex);
23     }
24 }

Let's focus on Line 11 List <String> configurations = getCandidateConfigurations (annotationMetadata, attributes); it will inject many automatic configuration classes (xxxAutoConfiguration) into the container, which is all the components needed to import this scene into the container and configure them.Let's follow up

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
            AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
        getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
    //...
    return configurations;
}

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    return EnableAutoConfiguration.class;
}

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    try {
        //From Class Path META-INF/spring.factories Load all default auto-configuration classes in
        Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                                 ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
        List<String> result = new ArrayList<String>();
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
            //Obtain EnableAutoConfiguration All specified values,that is EnableAutoConfiguration.class Value of
            String factoryClassNames = properties.getProperty(factoryClassName);
            result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
        }
        return result;
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
}
When SpringBoot starts, it gets the values specified by EnableAutoConfiguration from META-INF/spring.factories in the class path and imports them into the container as auto-configuration classes. The auto-configuration classes take effect and the auto-configuration is finished.EnableAutoConfiguration defaults to spring-boot-autoconfigure, as shown below

Finally, 96 AutoConfiguration classes were loaded and registered in the Spring container

The overall J2EE integration solution and automatic configuration are in spring-boot-autoconfigure-xxx.jar.In these auto-configuration classes, conditional annotations such as @ConditionalOnClass are used to determine if certain dependent packages have been imported, and the corresponding objects are registered with @Bean for auto-configuration.Later we'll have a separate article on automatic configuration

Posted by mightymaster on Wed, 13 Nov 2019 19:46:45 -0800