On the principle of automatic configuration of spring boot

The operation principle of spring boot is based on the automatic configuration of spring boot. If we want to use spring boot skillfully, we must study it deeply.

1:

Select the dependent version of SpringBoot:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
    <relativePath/>
</parent>

First, let's take a look at what auto configuration classes spring boot automatically starts for us when we start a spring boot project.

Operation (choose one of the following three methods):

(1) Set properties in application.properties:

debug=true

(2) Run the xxx.jar file through the cmd command window

java -jar xxx.jar --debug

(3) Set runtime parameters in Idea

Result:

--------------------

--------------------

Two:

Next, we need to learn an annotation @ SpringBootApplication, which is a composite annotation. Its core function is provided by the @ EnableAutoConfiguration annotation.

OK, then let's look at the source code of @ EnableAutoConfiguration:

@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 {};

}

Brothers, look!!! There is an @ Import annotation in it. Have you noticed??? Its function is very important!

Its purpose is to import the AutoConfigurationImportSelector class into the Spring IOC container. So let's go in and have a look. There is a selectImports method in this class. The specific source code is as follows:

 public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.filter(configurations, autoConfigurationMetadata);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return StringUtils.toStringArray(configurations);
        }
    }

In this method, a static method loadMetadata(ClassLoader classLoader) of AutoConfigurationMetadataLoader class is called.

public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
        return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties");
    }

This method is used to scan the jar package with "META-INF/spring-autoconfigure-metadata.properties" file, while our spring-boot-autoconfigure-2.0.1RELEASE.jar has the spring.factories file, and then we will open it to check the specific autoconfiguration of this file. As shown in the figure:

Then I choose a more familiar HttpEncodingAutoConfiguration class

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.boot.autoconfigure.web.servlet;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.http.HttpEncodingProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.filter.CharacterEncodingFilter;

@Configuration //Indicates that this is a configuration class. Like the previously written configuration file, components can also be added to the container
@EnableConfigurationProperties({HttpEncodingProperties.class}) //Start the ConfigurationProperties function of the specified class; bind the corresponding value in the configuration file with HttpEncodingProperties; and add HttpEncodingProperties to the ioc container
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class}) //Determine whether the current project has this class of characterencodingfilter; spring MVC filter for scrambling;
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)//Judge whether a configuration spring.http.encoding.enabled exists in the configuration file; if not, it is also valid / / even if we do not configure spring.http.encoding.enabled = true in the configuration file, it is valid by default;
public class HttpEncodingAutoConfiguration {
    private final HttpEncodingProperties properties;
    
    //In the case of only one parameter constructor, the value of the parameter is taken from the container
    public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
        this.properties = properties;
    }

    @Bean    //Add a component to the container. Some values of this component need to be obtained from properties
    @ConditionalOnMissingBean      //Judge the container does not have this component?
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpEncodingProperties.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpEncodingProperties.Type.RESPONSE));
        return filter;
    }

    @Bean
    public HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
        return new HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer(this.properties);
    }

    private static class LocaleCharsetMappingsCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
        private final HttpEncodingProperties properties;

        LocaleCharsetMappingsCustomizer(HttpEncodingProperties properties) {
            this.properties = properties;
        }

        public void customize(ConfigurableServletWebServerFactory factory) {
            if (this.properties.getMapping() != null) {
                factory.setLocaleCharsetMappings(this.properties.getMapping());
            }

        }

        public int getOrder() {
            return 0;
        }
    }
}

The above source code determines whether the configuration class is effective according to the current different conditions. Once the configuration class is effective, it will add various components to the container. The properties of these components are obtained from the corresponding properties class, and each property in these classes is bound to the configuration file;
 

All the properties that can be configured in the configuration file are encapsulated in the xxxproperties class; the configuration file can refer to a function if it can be configured
The corresponding attribute class, for example:

@ConfigurationProperties(
    prefix = "spring.http.encoding"
)        //Get the specified value and bean's properties from the configuration file for binding
public class HttpEncodingProperties {
    public static final Charset DEFAULT_CHARSET;
    private Charset charset;
    private Boolean force;
    private Boolean forceRequest;
    private Boolean forceResponse;
    private Map<Locale, Charset> mapping;

    public HttpEncodingProperties() {
        this.charset = DEFAULT_CHARSET;
    }

    public Charset getCharset() {
        return this.charset;
    }

    public void setCharset(Charset charset) {
        this.charset = charset;
    }

    public boolean isForce() {
        return Boolean.TRUE.equals(this.force);
    }

    public void setForce(boolean force) {
        this.force = force;
    }

    public boolean isForceRequest() {
        return Boolean.TRUE.equals(this.forceRequest);
    }

    public void setForceRequest(boolean forceRequest) {
        this.forceRequest = forceRequest;
    }

    public boolean isForceResponse() {
        return Boolean.TRUE.equals(this.forceResponse);
    }

    public void setForceResponse(boolean forceResponse) {
        this.forceResponse = forceResponse;
    }

    public Map<Locale, Charset> getMapping() {
        return this.mapping;
    }

    public void setMapping(Map<Locale, Charset> mapping) {
        this.mapping = mapping;
    }

    public boolean shouldForce(HttpEncodingProperties.Type type) {
        Boolean force = type == HttpEncodingProperties.Type.REQUEST ? this.forceRequest : this.forceResponse;
        if (force == null) {
            force = this.force;
        }

        if (force == null) {
            force = type == HttpEncodingProperties.Type.REQUEST;
        }

        return force;
    }

    static {
        DEFAULT_CHARSET = StandardCharsets.UTF_8;
    }

    public static enum Type {
        REQUEST,
        RESPONSE;

        private Type() {
        }
    }
}

Conclusion:

1) Spring boot will load a large number of auto configuration classes
2) Let's see if the function we need has the auto configuration class written by SpringBoot by default;
3) Let's see which components are configured in this auto configuration class. (as long as we have components to use, we don't need to configure them again.)
4) When you add components to a container's auto configuration class, you get some properties from the properties class. We can specify the values of these properties in the configuration file;
5) Xxxautoconfiguration: autoconfiguration classes; adding components to containers
xxxxProperties: encapsulates the related properties in the configuration file;
 

 

 

 

 

 

 

 

 

 

Published 8 original articles, won praise 3, 773 visitors
Private letter follow

Tags: Spring encoding SpringBoot Java

Posted on Sun, 12 Jan 2020 08:06:29 -0500 by TurtleDove