Microservice architecture learns how SpringBoot works

“This is the 10th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

About the author

  • The authors introduce

🍓 Blog home Page: author home page 🍓 Introduction: High-quality creator in the JAVA field 🥇, a junior student 🎓, participated in various provincial and national competitions during school, and won a series of honors 🍓, Ali Cloud expert blogger, 51CTO expert blogger, follow me: Pay attention to my learning materials, document download all have, regularly update the article every day, inspirational to do a JAVA senior program ape 👨💻


Operation principle exploration

Maven: HelloSpringBoot: HelloSpringBoot: Maven: HelloSpringBoot: Maven: HelloSpringBoot: Maven: HelloSpringBoot: Maven: HelloSpringBoot: Maven: HelloSpringBoot: Maven: HelloSpringBoot: Maven: HelloSpringBoot: Maven

1. Parent dependencies

pom.xml

  • Automatic configuration
  • Spring-boot-dependencies:
  • When we write or import Springboot dependencies, we do not need to specify the version because of the repository

1, it is mainly dependent on a parent project, mainly manage project resource filtering and plug-ins!

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

2, click in, find there is a parent dependency

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

3. This is where all dependencies in the SpringBoot application are managed, the Version control center of SpringBoot.

4, later we import dependency default is do not need to write version; However, if the imported package is not managed in a dependency, you need to manually configure the version;

2. The initiator spring-boot-starter

  • Rely on

    <dependency>        								 		       		<groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter</artifactId>
    </dependency>
    Copy the code
  • Springboot-boot-starter-xxx is the boot scenario of Springboot

  • Spring-boot-starter-web, for example, automatically imports all web dependencies for us

  • Springboot will turn all the functional scenarios into individual initiators

  • What function do we want to use, we just need to find the corresponding initiator start

3. Main program

3.1. Default main startup class

package com.sxau;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplicationTo annotate a main program class// This is a Spring Boot application
public class Springboot01HelloworldApplication {
    // Start a service
    public static void main(String[] args) { SpringApplication.run(Springboot01HelloworldApplication.class, args); }}Copy the code

But ** A simple startup class is not simple! ** What do these annotations do

3.2. Annotations (@SpringBootApplication)

  • Purpose: Annotation on a class indicates that this class is the main configuration for SpringBoot

  • SpringBoot should run the class’s main method to start the SpringBoot application;

  • Go to this annotation: there are many other annotations on it!

    @SpringBootConfigurationSpringboot configuration@ConfigurationThe spring configuration class@ComponentDescription is a Spring component@EnableAutoConfigurationAutomatic package importFilters = {@filter (type = filtertype.custom, classes = {typeExCludefilter.class}), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} )
    // @interface User-defined interface
    public @interface SpringBootApplication {
        / /...
    }
    Copy the code

@ComponentScan

  • This annotation is important in Spring and corresponds to elements in the XML configuration.

  • What it does: Automatically scans and loads qualified components or beans, and loads the bean definition into the IOC container

@SpringBootConfiguration

  • SpringBoot configuration class, marked on a class, indicating that this is a SpringBoot configuration class.

  • Let’s go ahead and look at this annotation

    // Click inside to get @Component below
    @Configuration
    public @interface SpringBootConfiguration {
        @aliasfor (// @aliasfor defines alias annotation = configuration.class)
        boolean proxyBeanMethods(a) default true;
    }
    
    @Component
    public @interface Configuration {}
    Copy the code
  • @Configuration indicates that this is a Spring Configuration class. The Configuration class is the corresponding SPRING XML Configuration file.

  • @Component The launcher class itself is a Component in Spring that launches the application!

  • Let’s go back to the SpringBootApplication annotations.

@EnableAutoConfiguration

  • Enable the automatic configuration function

    • We used to have to configure things ourselves, but now SpringBoot does it for us;
    • @enableAutoConfiguration tells SpringBoot to enable automatic configuration so that the automatic configuration takes effect.

    Click on the comments to continue the view:

  • @autoConfigurationPackage: Automatic configuration package

    @Import({Registrar.class})
    public @interface AutoConfigurationPackage {
    }
    Copy the code
    • @import: Spring’s underlying annotation @import imports a component into the container

    • Registrar. Class Automatically configure the package registration to scan the main launcher package and all the components in the sub-package to the Spring container.

    • This analysis done, back up, continue

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

    • AutoConfigurationImportSelector: automatic configuration import selector, then it will import the selector which components? Let’s click on this class to see the source code:

      // Get all the configuration
      List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
      Copy the code
    • Get the candidate configuration

      protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
          // Corresponding to the following method
          / / here getSpringFactoriesLoaderFactoryClass () method
          // Return the annotation class that started the automatic import configuration file; 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;
      }
      
      // corresponds to the first parameter in the loadFactoryNames method of the above class
      / / here getSpringFactoriesLoaderFactoryClass () method
      // Return the annotation class that started the automatic import configuration file; EnableAutoConfiguration
       protectedClass<? > getSpringFactoriesLoaderFactoryClass() {return EnableAutoConfiguration.class;
       }
      Copy the code
    • This method getCandidateConfigurations () call again SpringFactoriesLoader static method of a class! We go to the loadFactoryNames() method of the SpringFactoriesLoader class to get all the load configuration

      public static List<String> loadFactoryNames(Class<? > factoryType,@Nullable ClassLoader classLoader) {
          String factoryClassName = factoryClass.getName();
          // Here it calls the loadSpringFactories method again
          return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
      }
      Copy the code
    • Let’s go ahead and check out the loadSpringFactories method

      • Project Resources:META-INF/spring.factories
      • System resources:META-INF/spring.factories
      • All nextElement (automatic configuration) is configured from these resources, grouped as Properties
      // Load all the resources into the configuration class (extract the following for analysis, line 13)
      Properties properties = PropertiesLoaderUtils.loadProperties(resource);
      Copy the code
      private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
          // Get the classLoader, and you can see that this is the EnableAutoConfiguration class itself
          MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
              if(result ! =null) {
                  return result;
              } else {
                  try {
                  // Get a resource "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();
                  // Determine if there are any more elements, loop through the read resource and wrap it into a 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); }}}Copy the code
    • Find a file that appears multiple times: Spring.Factories, and search it globally

3.3, spring. Factories

We opened Spring.Factories from the source and saw a lot of auto-configured files. This is where auto-configuration comes from!

WebMvcAutoConfiguration

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

You can see that these are JavaConfig configuration classes, and have injected some beans, you can find some of their own knowledge of the class, look familiar with it!

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.

4. Conclusions:

  1. SpringBoot starts from the classpathMETA-INF/spring.factoriesTo deriveEnableAutoConfigurationThe specified value
  2. Import these values into the container as auto-configuration classes, which take effect and help us with auto-configuration work.
  3. We used to need to configure things automatically, but SpringBoot now does it for us
  4. The integration of JavaEE, the overall solution and the auto-configuration stuff are all therespringboot-autoconfigureJar package;
  5. It will return all the components that need to be imported as class names, and they will be added to the container
  6. It will import a lot of autoconfiguration classes into the container (xxxAutoConfiguration), that is, import all the components needed for this scenario into the container and automatically configure it, @Configuration (javaConfig);
  7. With the automatic configuration class, we do not need to manually write configuration injection function components;

Now we should probably understand the operating principle of SpringBoot, and we will deepen it again!

Start the

1, not simple method

I initially thought I was running a main method, but instead I started a service;

package com.sxau;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication // to annotate a main program class
// This is a Spring Boot application
public class Springboot01HelloworldApplication {
    / / this method returns a ConfigurableApplicationContext object
    // Parameter 1: application entry class; Parameter 2: command line parameter
    public static void main(String[] args) { SpringApplication.run(Springboot01HelloworldApplication.class, args); }}Copy the code

SpringApplication. Analysis of the run

  • The analysis of this method can be divided into two parts
  • One is instantiation of SpringApplication,
  • Second, the execution of the RUN method;

2, SpringApplication

This class does four 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

View the constructor:

public SpringApplication(ResourceLoader resourceLoader, Class
       ... primarySources) {
        this.sources = new LinkedHashSet();
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = Collections.emptySet();
        this.isCustomEnvironment = false;
        this.lazyInitialization = false;
        this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
        this.applicationStartup = ApplicationStartup.DEFAULT;
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        this.bootstrappers = new ArrayList(this.getSpringFactoriesInstances(Bootstrapper.class));
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
}
Copy the code

3. Process analysis of run method

Follow the source code and this picture can find out!

4, About SpringBoot, talk about your understanding;

  • Automatically.
  • run()
  • Take over the configuration of SpringMVC