Operation principle

For research purposes, we normally start with the parent project’s POM.xml.

pom.xml

The parent relies on spring-boot-starter-parent to manage resource filtering and plug-ins for the project


<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.5. RELEASE</version>
    <relativePath/> <! -- lookup parent from repository -->
</parent>
Copy the code

< span style = “box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 14px! Important; word-break: inherit! Important;”


<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.2.5. RELEASE</version>
    <relativePath>. /.. /spring-boot-dependencies</relativePath>
</parent>
Copy the code

Initiator: spring-boot-starter-xxx: indicates the springboot scenario initiator

Spring-boot-starter-web: imports web-dependent components

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

The main program

@SpringBootApplication

Springboot is a springboot application that is launched by running the mian method of this class.

@SpringBootApplication // This is a main application class, indicating that this is a SpringBoot application
public class Springboot01HelloworldApplication {

    public static void main(String[] args) {
        // instead of executing a method, a service is started.SpringApplication.run(Springboot01HelloworldApplication.class, args); }}Copy the code

Click @SpringBootApplication to continue research, you will find @SpringBootConfiguration, @EnableAutoConfiguration, @ComponentScan these three annotations

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} )
Copy the code
  1. @ComponentScan: Spring automatically scans packages

This we saw in the Spring configuration file is used to automatically scan and load qualified components or beans, and load the beans into the IOC container.

  1. @springBootConfiguration: configuration class for SpringBoot

The annotation on a class indicates that the class is the springBoot configuration class, in this case it indicates that the SpringBootApplication class is the SpringBoot configuration class.

If we go ahead and click @springBootConfiguration, we’ll see @Configuration

2.1@Configuration: Configuration class, used to configure Spring XML files

If we go ahead and click on @Configuration, we’ll see the @Component annotation.

2.2 @Component: Component, which indicates that the startup class itself is a Component that starts the application.

At this point, the @springBootConfiguration line, we’re done.

  1. @EnableAutoConfiguration: Enable automatic assembly and pass@EnableAutoConfigurationTo help us automatically configure what we needed to configure earlier.

We continue to point @ EnableAutoConfiguration in check, will find @ @ AutoConfigurationPackage and Import ({AutoConfigurationImportSelector. Class}) the two annotations.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<? >[] exclude()default {};

    String[] excludeName() default {};
}
Copy the code

3.1@ AutoConfigurationPackage

Click through and the @import ({Registrar. Class}) annotation appears

3.1.1@import ({register.class}) : The spring underlying annotation imports a component into the container

Registrar. Class: Scan all the components in the main launcher package and any subpackages under that package into the Spring container.

So now we’re done with the at sign AutoConfigurationPackage line.

3.2 @ Import ({AutoConfigurationImportSelector. Class}) : give the container Import components

AutoConfigurationImportSelector. Class: automatic assembling imported selector.

Import selector analysis:

  1. Let’s click inAutoConfigurationImportSelector.classExplore the source code of this class,

  1. We clickgetCandidateConfigurationsFurther analysis
    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;
    }
Copy the code

2.1 use the getSpringFactoriesLoaderFactoryClass () method, we see return to the beginning start the automatic configuration file annotation class EnableAutoConfiguration. Class

    protectedClass<? > getSpringFactoriesLoaderFactoryClass() {return EnableAutoConfiguration.class;
    }
Copy the code

2.2 Found that it calls the static method of the SpringFactoriesLoader class. We click loadFactoryNames to loadFactoryNames().

public static List<String> loadFactoryNames(Class<? > factoryType,@Nullable ClassLoader classLoader) {
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == null) {
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }

        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    }
Copy the code

Check that it calls the loadSpringFactories() method again

    private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if(result ! =null) {
            return result;
        } else {
            HashMap result = new HashMap();

            try {
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) { Entry<? ,? > entry = (Entry)var6.next(); String factoryTypeName = ((String)entry.getKey()).trim(); String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); String[] var10 = factoryImplementationNames;int var11 = factoryImplementationNames.length;

                        for(int var12 = 0; var12 < var11; ++var12) {
                            String factoryImplementationName = var10[var12];
                            ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                                return new ArrayList();
                            })).add(factoryImplementationName.trim());
                        }
                    }
                }

                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14); }}}Copy the code

Source code analysis:

  1. MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);Getting the classLoader, we return and you can see that what we got here is the EnableAutoConfiguration annotation class itself
  2. Enumeration<URL> urls = classLoader ! = null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");Get a resource “meta-INF /spring.factories”
  3. whileLooping, the read resource is iterated, encapsulated as a Properties

Spring. Factories file

WebMvcAutoConfiguration

Let’s open one of the auto-configuration classes above, such as WebMvcAutoConfiguration

Are familiar configuration, so, realize automatic configuration from the classpath to search all the meta-inf/spring. Factories configuration files, and the corresponding org. Springframework. Boot. Autoconfigure. The Configuration items under the package are instantiated by reflection into the corresponding IOC container Configuration classes in JavaConfig form annotated with @Configuration, which are then aggregated into an instance and loaded into the IOC container.

conclusion

  1. SpringBoot gets the value specified by EnableAutoConfiguration from the META-INF/ Spring. factories in the classpath at startup
  2. Import these values into the container as auto-configuration classes, which take effect and help us with auto-configuration work.
  3. The entire J2EE solution and automatic configuration is in the Springboot-Autoconfigure JAR package;
  4. It imports a lot of auto-configuration classes (xxxAutoConfiguration) into the container, which is to import all the components needed for this scenario into the container and configure them;
  5. With the automatic configuration class, we do not need to manually write configuration injection function components;

The main start class

SpringApplication

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

Analysis:

  1. The entrance of the SpringbootApplication. Class: application parameters
  2. Args: command line parameter
  3. This method returns aConfigurableApplicationContextobject

SpringApplication does the following things:

  1. Determine whether the type of application is a normal project or a Web project
  2. Find and load all available initializers into the Initializers property
  3. Find all application listeners and set them to the Listeners properties
  4. Infer and set the definition class of the main method to find the running main class