Springboot 2 -- principle of automatic assembly

Principle of boot loading configuration class

SpringBoot is started through @ SpringBootApplication. In the previous chapter, we found that after startup, in addition to the components we added to the IOC container, other components were automatically added to the IOC container. We guess they were added through this annotation. Let's take a look at @ SpringBootApplication first

@SpringBootApplication

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

@The SpringBootApplication annotation is a composite annotation, which is mainly composed of the following three annotations

  • @SpringBoot configuration: this annotation tells SpringBoot that I am the main program
  • @ComponentScan: we learned it when learning Spring. This is to enable annotation scanning
  • @Enable autoconfiguration: from the literal meaning of the word, it means automatic configuration. Let's focus on this annotation

@EnableAutoConfiguration

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

We found that this annotation is also a composite annotation. Let's look at what these two annotations do one by one

  • @AutoConfigurationPackage

    Explain from the surface English words: automatically configure the package, that is, this annotation may be the package that manages all components. This annotation automatically creates a component of the Registrar class

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

      Take a look through breakpoint debugging

      The first is the parameter metadata, which means that the annotation is marked on which class. Through layer by layer analysis, we know that this class is marked on our main application

      We mainly look at the following code. We find that through this code, we find the full path of the package where our main program is located, and then use the Registrar to import a series of components into the container to import all components under a specified package.

          static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
              Registrar() {
              }
      		//Focus on this method
              public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
                  AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
              }
      
              public Set<Object> determineImports(AnnotationMetadata metadata) {
                  return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
              }
          }
      
  • AutoConfigurationImportSelector

    This configuration returns 131 objects. It is found that these objects are automatically injected. Let's go in and have a look

    After going in, we found that we used the factory to load map < string, list > loadspringfactories (@ nullable classloader classloader) to get all the components, and we got the address of the loaded components

    We imported this file into spring boot autoconfigure. After browsing it, we found that she just assembled 131 components for us

Turn on automatic configuration items on demand

Output the names of all components in the IOC container through the console. We find that not all of the 131 components are loaded into the IOC container. Here, we use the @ Conditional described in the previous chapter. Finally, it will be configured on demand. Let's pick a few

DispatcherServletAutoConfiguration

This component automatically injects the front-end controller into the IOC container. This is a successful case. We can find the dispatcher servlet in the console output

@AutoConfigureOrder(-2147483648)
@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({DispatcherServlet.class}) //Only when there is a dispatcher servlet class can it be injected automatically. The dispatcher servlet class exists
@AutoConfigureAfter({ServletWebServerFactoryAutoConfiguration.class}) 
public class DispatcherServletAutoConfiguration {

CacheAutoConfiguration

Interestingly, @ ConditionalOnMissingBean will be marked on many methods, which means that if the user is configured, it will be based on the user's. If the user is not configured, the components automatically created by the system will be used

public class CacheAutoConfiguration {
    public CacheAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean
    public CacheManagerCustomizers cacheManagerCustomizers(ObjectProvider<CacheManagerCustomizer<?>> customizers) {
        return new CacheManagerCustomizers((List)customizers.orderedStream().collect(Collectors.toList()));
    }
}

summary

  • SpringBoot loads all the autoconfiguration classes xxxxconfiguration first

  • Each automatic configuration class takes effect according to conditions, and will bind the value specified in the configuration file by default. Take it from xxproperties. xxxProperties is bound to the configuration file

  • The effective configuration class will assemble many components in the container

  • As long as these components are in the container, they are equivalent to these functions

  • Customized configuration

    • Users directly replace the underlying components with @ Bean
    • The user can modify the value of the configuration file obtained by this component.

Tags: Java Spring Spring Boot

Posted on Wed, 10 Nov 2021 04:59:52 -0500 by dantone