Beginner SpringBoot - automatic configuration

Auto configuration

1.1 automatically configure Tomcat

  • Introduce tomcat dependency
   
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <version>2.3.12.RELEASE</version>
      <scope>compile</scope>
</dependency>
  • Configure Tomcat

1.2 auto configure spring MVC

  • Introducing a full set of spring MVC components
  • Automatically configure common components of SPringleMVC
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.2.15.RELEASE</version>
      <scope>compile</scope>
    </dependency>
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.15.RELEASE</version>
      <scope>compile</scope>
</dependency>
  • Common functions
    • dispatchServlet (forwarding)
    • multipartResolver (file upload)
    • Viewresolver
    • Characterencoding filter
  • Show the method of corresponding components in the container
@SpringBootApplication
public class MainApplication {

    public static void main(String[] args) {
//        springApplication.run(MainApplication.class,args);
        // 1. Return to IOC container
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        // 2. Check the components in the container
        String[] names = run.getBeanDefinitionNames();
        for(String name : names){
            System.out.println(name);
        }
    }
}

1.3 default package structure

  • All sub package components of the package where the main program is located will be scanned by default

    ```
    

    com
    ± example
    ± myapplication
    ± Application.java
    |
    ± customer
    | ± Customer.java
    | ± CustomerController.java
    | ± CustomerService.java
    | ± CustomerRepository.java
    |
    ± order
    ± Order.java
    ± OrderController.java
    ± OrderService.java
    ± OrderRepository.java
    ```

  • No previous package scanning is required

  • If you want to set up your own package scanning

@SpringBootApplication(scanBasePackages = "com.atguigu") //Add on main class
@ComponentScan //Add the annotation of package scanning on the specific class
 Be careful not to pack any more SpringBootApplication Add package scan annotation on because SpringBootApplication It's already there componentScan Annotated
  • *@SpringBootApplication is a composite class
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan

1.4 auto configuration has many default values

  • The default configuration is finally mapped to a class
  • The value of the configuration file is eventually bound to each class, which creates objects in the container

1.5 loading automatic configuration items on demand

  • Very many starter s
  • After introducing those scenarios, the automatic configuration of this scenario will be enabled
  • All spring boot autoconfigure functions depend on spring boot autoconfigure
  1. Spring boot web project needs to introduce spring boot starter web dependency

  2. Spring boot starter web depends on spring boot starter

  3. Spring boot starter requires spring boot autoconfigure to complete automatic configuration

 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
      <version>2.3.12.RELEASE</version>
      <scope>compile</scope>
 </dependency>

2. Container function

2.1 component addition

  1. @Configuration (tell IOC that this class is a configuration class)

    @Configuration(proxyBeanMethods = false)
    			   //Tell SpringBoot that this is a configuration class = = configuration file
                   //The configuration file can accomplish anything the configuration class can
                   //At the same time, the components created by @ Configuration are also loaded into the container
                   //The components created by default are single instance
    public class MyConfig {
    
        @Bean //Add a component to the container, take the method name as the id of the component, the return type is the type of the component, and the return value is the instance of the component in the container
        public User user01(){
            return new User("Zhang San");
        }
    
        @Bean("tomcat111")
        public Pet getPet(){
            return  new Pet("tomcat","12");
        }
    
    }
    
    • The components registered in the class annotated with Configuration are singletons

      // Configuration.class
      @Target({ElementType.TYPE})
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      @Component
      public @interface Configuration {
       @AliasFor(
           annotation = Component.class
       )
       String value() default "";
       boolean proxyBeanMethods() default true; //The default is true, which indicates that the method will be proxied
      }
      

    /*
    Object created in container Ioc: MyConfig E n h a n c e r B y S p r i n g C G L I B EnhancerBySpringCGLIB EnhancerBySpringCGLIBd02ce854@13cda7c9
    Is the object of the proxy enhanced by the container. When proxyBeanMethods is true by default
    When the proxy object calls the user01 method, it will first look for the corresponding component in the container
    1. If yes, return
    2. If none, create
    In short, keep the component single instance
    */

    - proxyBeanMethods method:agent bean method
    
    ​```java
    Full(proxyBeanMethods = true) //Using the proxy method, the singleton returns the same object and applies it to component dependencies
    Lite(proxyBeanMethods = false) //Multiple instances return different objects each time. Advantages: skip checking the container and spring boot starts quickly
    
  2. @Bean,@Component,@Controller,@Service,@Repository

  3. @ComponentScan,@Import

@import must be written in the package scanning range. When importing, it is an array. The component name of the imported component is package name + class name

  1. @Conditional: conditional assembly. It is loaded into the container only when the conditional is met
More important
ConditionalOnBean() //Only when this class exists in the container can the component be registered
ConditionalOnMissingBean //The component is registered only if it does not exist in the container
ConditionalOnMissingClass //The component is registered only if it does not exist in the container
ConditionalOnClass //Only when this class exists in the container can the component be registered
ConditionalOnResource //What happens when there is a resource in the file
ConditionalOnJava     //Components are registered only after a java version is selected by default
ConditionalOnWebApplication  //Components are registered only when it is a web application
ConditionalOnNotWebApplication //Components are registered only when they are not web applications
ConditionalOnProperty //Only when a component has a property can it be registered

Example

@Configuration //Tell SpringBoot that this is a configuration class = = configuration file
               //The configuration file can accomplish anything the configuration class can
               //At the same time, the components created by @ Configuration are also loaded into the container
               //The components created by default are single instance
public class MyConfig {

    @ConditionalOnMissingBean(name = "tomcat")
    @Bean //Add a component to the container, take the method name as the id of the component, the return type is the type of the component, and the return value is the instance of the component in the container
    public User user01(){
        return new User("Zhang San");
    }

    public Pet getPet(){
        return  new Pet("tomcat","12");
    }
}

2.2 import of native configuration file

  1. @ImportResource * *: written on the configuration class**

    Used to import xml configuration file objects into the IOC container of springboot

    @Configuration //Tell SpringBoot that this is a configuration class = = configuration file
    
    @ImportResource("classpath:beans.xml")              
    
    public class MyConfig {
        @Bean //Add a component to the container, take the method name as the id of the component, the return type is the type of the component, and the return value is the instance of the component in the container
        public User user01(){
            return new User("Zhang San");
        } 
    }
    

2.3 configuration binding

  1. ConfigurationProperties
@Component  //Be sure to add component comments to add components to the container
@ConfigurationProperties(prefix = "mycar") //Setting the prefix will be displayed in application Properties to find
public class Car {
    private String brand;
    private  String price;

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public String getBrand() {
        return brand;
    }

    public String getPrice() {
        return price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", price='" + price + '\'' +
                '}';
    }
}
  1. @EnableCofigurationProperties + @ConfigurationProperties
/*
Profile class
*/
@Configuration
@EnableConfigurationProperties(Car.class) //Make files available
public class MyConfig {
    @Bean //Add a component to the container, take the method name as the id of the component, the return type is the type of the component, and the return value is the instance of the component in the container
    public User user01(){
        return new User("Zhang San");
    }

    public Pet getPet(){
        return  new Pet("tomcat","12");
    }
}

/*
You need to add the component information to obtain the corresponding value
*/
@ConfigurationProperties(prefix = "mycar") //Setting the prefix will be displayed in application Properties to find
public class Car {
    private String brand;
    private  String price;

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public String getBrand() {
        return brand;
    }

    public String getPrice() {
        return price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", price='" + price + '\'' +
                '}';
    }
}

Method 1 is mainly used for self written classes. Method 1 is mainly used for data binding of third-party classes

3. Introduction to automatic configuration principle

3.1 full signature of springbootapplication (idea:ctrl+n for search)

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(			//Three are its core annotations, or spring boot application is a composite of the three
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication
  1. @SpringBootConfiguration
/**
* 	SpringBootConfiguration.class source code
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration	//Represents that the current configuration class is a configuration class, which means that SpringBootApplication is still a configuration class and a core configuration class
@Indexed
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}
  1. @ComponentScan

Specify which packages to scan. See the Spring annotation for details;

  1. @EnableAutoConfiguration (key, specify default package rules)

Function: help the SpringBoot application load all qualified @ Configuration configurations into the current SpringBoot, create a Bean corresponding to the Configuration class, and hand over the Bean entity to the IoC container for management.

/*
* EnableAutoConfiguration source code
*/
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}
  • AutoConfigurationPackage autoconfiguration package
/*
*	AutoConfigurationPackage source code
*/
@Import({AutoConfigurationPackages.Registrar.class})  //Import a component into the container
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};
    Class<?>[] basePackageClasses() default {};
}

The meaning of using import to import a register: batch import some components

  • View autoconfigurationpackages Registrar. Class to find out what registrar has registered.
public abstract class AutoConfigurationPackages {
    private static final Log logger = LogFactory.getLog(AutoConfigurationPackages.class);
    private static final String BEAN = AutoConfigurationPackages.class.getName();

    public AutoConfigurationPackages() {
    }

  	...
    ...
    ...

    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }

        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
        }
/*
AnnotationMetadata:Indicates the source information of the annotation. Since springboot - > enableautoconfiguration - > autoconfigurationpackage - > autoconfigurationpackages, the information displayed when displaying the source information is the MainApplication information, that is, the package name
 It is equivalent to taking the package of the main configuration of a @ SpringBootApplication annotation to com ruan. Boot, register batch registers the components in a package
*/
        
        
        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
        }
    }
}
  • @Import({AutoConfigurationImportSelector.class})

Focus on autoconfigurationimportselector class->selectImports->this. Getautoconfigurationentry (annotation metadata) to batch import components into the container

/*
* this.getAutoConfigurationEntry(annotationMetadata) Method implementation
*/
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            //1.getCandidateConfigurations obtains the configuration classes (components) that need to be imported into the container
            //2.SpringFactoriesLoader.loadFactoryNames, spring's factory loader, to load some configuration classes
            //Use the private static map < string, list < string > > loadspringfactories (@ nullable classloader classloader) method of the factory loader to obtain all components
            //3. The loadspringfactories method will be in meta-inf / spring Load a file from the factories location.
            //   Scan all meta-inf / spring.net files in the current system factories
            //   Spring-boot-autoconfigure-2.3.12 in the core jar package RELEASE. Jar contains 127 elements and all classes that spring boot needs to load into the container as soon as it starts.
            
            
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

3.2 on demand configuration

It is known from the above that when springboot is started, how to find the corresponding components in the automatic configuration, but not all components must be loaded into the components. There is a situation of on-demand configuration (127 of the above autoconfigure are not loaded, and the corresponding scene dependencies need to be imported, i.e. conditional assembly rules)

In other words: all automatic configurations of 127 scenes are loaded when they are started, but not all are assembled

3.3 modifying the default configuration

    @Bean
    @ConditionalOnBean({MultipartResolver.class}) //There are such components in the container
    @ConditionalOnMissingBean(	//This name is not in the container
         name = {"multipartResolver"}
    )
    public MultipartResolver multipartResolver(MultipartResolver resolver) {
         //@The method of Bean annotation passes in the object parameter, and the parameter value will be found from the container
         // SpringMvc multipartResolver, some user configured file upload parsers do not meet the specification
         return resolver;
    }
	//A file upload parser is added to the container

4. Summary

  • SpringBoot loads all auto configuration classes first
  • Each autoconfiguration class takes effect according to conditions
  • The effective configuration class will assemble many components according to the container
  • As long as these components are included, they are equivalent to these functions
  • As long as the user has his own configuration, the user's priority will prevail

Xxxautoconfiguration - > component - > which value in xxxproperties - > application properties

Keywords: Java Spring mvc

Added by python_q on Sat, 01 Jan 2022 12:13:53 +0200