Analysis of the basic principles of SpringBoot startup

pom.xml

Paternal dependence

The parent project is mainly dependent on a parent project, mainly to manage the resource filtering and plug-ins of 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>

Click in and find that there is another parent dependency


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

This is the place to truly manage all dependent versions in the SpringBoot application, the version control center of SpringBoot;

In the future, we import dependencies by default without writing the version; but if the imported package is not managed in the dependency, you need to manually configure the version;

Launcher


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

springboot-boot-starter-xxx: is the scene starter of spring-boot

spring-boot-starter-web: Help us import the components that the web module depends on for normal operation;

SpringBoot extracts all the functional scenarios into one starter (starter), only need to introduce these starters in the project, all related dependencies will be imported in, we import what kind of function we want to use The scene starter is enough; we can also customize the starter ourselves in the future;

Main start class

//@SpringBootApplication 来标注一个主程序类
//说明这是一个Spring Boot应用
@SpringBootApplication
public class SpringbootApplication {
    
    

   public static void main(String[] args) {
    
    
     //以为是启动了一个方法,没想到启动了一个服务
      SpringApplication.run(SpringbootApplication.class, args);
   }

}

@SpringBootApplication

Function: Annotate a certain class to indicate that this class is the main configuration class of SpringBoot, and SpringBoot should run the main method of this class to start the SpringBoot application;


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

@ComponentScan

j corresponds to the element in the XML configuration.

Function: Automatically scan and load qualified components or beans, and load this bean definition into the IOC container

@SpringBootConfiguration

Function: The configuration class of SpringBoot, marked on a certain class, indicates that this is a configuration class of SpringBoot;

We continue to go into this annotation to view

// 点进去得到下面的 @Component
@Configuration
public @interface SpringBootConfiguration {
    
    }

@Component
public @interface Configuration {
    
    }

The @Configuration here means that this is a configuration class, and the configuration class is the xml configuration file corresponding to Spring ;

The @Component inside means that the startup class itself is just a component in Spring, responsible for starting the application !

@EnableAutoConfiguration

@EnableAutoConfiguration tells SpringBoot to turn on the automatic configuration function, so that the automatic configuration can take effect;
@AutoConfigurationPackage: automatic configuration package

@Import({
    
    Registrar.class})
public @interface AutoConfigurationPackage {
    
    
}

@import: Spring bottom annotation @import, import a component into the container

Registrar.class Function: Scan all components in the package where the main startup class is located and all sub-packages under the package to the Spring container;

After this analysis is over, go back to the previous step and continue to read

@Import({AutoConfigurationImportSelector.class}): Import components to the container;

AutoConfigurationImportSelector : Automatically configure the import selector, so which component selectors will it import? We click to go to this category to see the source code:

// 获得候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    
    
    //这里的getSpringFactoriesLoaderFactoryClass()方法
    //返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration
    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;
}

A method is called (a static method of the SpringFactoriesLoader class)

SpringFactoriesLoader class loadFactoryNames() method

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
    
    
    String factoryClassName = factoryClass.getName();
    //这里它又调用了 loadSpringFactories 方法
    return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

loadSpringFactories 方法

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    
    
    //获得classLoader , 我们返回可以看到这里得到的就是EnableAutoConfiguration标注的类本身
    MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
    if (result != null) {
    
    
        return result;
    } else {
    
    
        try {
    
    
            //去获取一个资源 "META-INF/spring.factories"
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
            LinkedMultiValueMap result = new LinkedMultiValueMap();

            //将读取到的资源遍历,封装成为一个Properties
            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 factoryClassName = ((String)entry.getKey()).trim();
                    String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                    int var10 = var9.length;

                    for(int var11 = 0; var11 < var10; ++var11) {
    
    
                        String factoryName = var9[var11];
                        result.add(factoryClassName, factoryName.trim());
                    }
                }
            }

            cache.put(classLoader, result);
            return result;
        } catch (IOException var13) {
    
    
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
        }
    }
}

Found a file that appeared multiple times: spring.factories

spring.factories

Open spring.factories and see a lot of auto-configuration files; this is the root of auto-configuration!

Therefore, the real implementation of automatic configuration is to search for all the META-INF/spring.factories configuration files from the classpath, and instantiate the configuration items under the corresponding org.springframework.boot.autoconfigure. package into corresponding annotations through reflection. The IOC container configuration class in the form of @Configuration JavaConfig, which is then aggregated into an instance and loaded into the IOC container.

to sum up

  1. When SpringBoot starts, it obtains the value specified by EnableAutoConfiguration from META-INF/spring.factories under the classpath.

  2. Import these values ​​into the container as the auto-configuration class, and the auto-configuration class will take effect, helping us with the auto-configuration work;

  3. The entire J2EE overall solution and automatic configuration are in the jar package of springboot-autoconfigure;

  4. It will import a lot of automatic configuration classes (xxxAutoConfiguration) into the container, that is, import all the components needed for this scenario into the container, and configure these components;

With the automatic configuration class, we can avoid the work of manually writing configuration injection functional components;

SpringApplication class


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

SpringApplication.run analysis

The analysis of this method is mainly divided into two parts, one is the instantiation of SpringApplication, and the other is the execution of the run method;

This class mainly does the following four things:

1. Infer whether the type of application is a normal project or a Web project

2. Find and load all available initializers and set them to the initializers property

3. Find out all application listeners and set them to the listeners property

4. Infer and set the definition class of the main method, and find the main class that runs

1. View the constructor:

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
    
    
    // ......
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    this.setInitializers(this.getSpringFactoriesInstances();
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

2. Run method process analysis

Insert picture description here

Guess you like

Origin blog.csdn.net/david2000999/article/details/114479288