Spring Boot 运行原理 - 实例分析(HttpEncodingAutoConfiguration)

在了解了Spring Boot的运作原理和主要注解后,现在来简单的分析一个Spring Boot内置的自动配置功能:http的编码配置。

我们在常规项目中配置Http编码的时候是在web.xml添加一个filter,如:


    CharacterEncodingFilter
    org.springframework.web.filter.CharacterEncodingFilter
    
        encoding
        utf-8
    
    
        forceEncoding
        true
    

自动配置要满足两个条件:

  1. 能配置CharacterEncodingFilter这个Bean;
  2. 能配置encoding和forceEncoding两个参数;

1 配置参数

在前面我们讲述了类型安全配置,Spring Boot也是基于这一点来实现的,这里的配置类可以在application.properties中直接设置,源码如下:

package org.springframework.boot.autoconfigure.web;

import java.nio.charset.Charset;
import java.util.Locale;
import java.util.Map;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "spring.http.encoding")// 在application.properties中配置的前缀是spring.http.encoding
public class HttpEncodingProperties {

    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); 

    private Charset charset = DEFAULT_CHARSET; // 默认的编码方式

    private Boolean force;

    private Boolean forceRequest;

    private Boolean forceResponse;

    private Map mapping;

    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 getMapping() {
        return this.mapping;
    }

    public void setMapping(Map mapping) {
        this.mapping = mapping;
    }

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

    enum Type {

        REQUEST, RESPONSE

    }

}

2 配置Bean

通过调用上述配置并根据条件配置CharacterEncodingFilter的Bean,看源码:

package org.springframework.boot.autoconfigure.web;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
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.web.HttpEncodingProperties.Type;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.filter.OrderedCharacterEncodingFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.filter.CharacterEncodingFilter;

@Configuration
@EnableConfigurationProperties(HttpEncodingProperties.class) // 开启属性注入
@ConditionalOnWebApplication
@ConditionalOnClass(CharacterEncodingFilter.class) // 当CharacterEncodingFilter在类路劲的条件下
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)// 当设置spring.http.encoding=enabled的情况下,如果没有设置默认是true,即符合条件
public class HttpEncodingAutoConfiguration {

    private final HttpEncodingProperties properties;

    public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
        this.properties = properties;
    }

    @Bean// 使用java方式配置CharacterEncodingFilter的Bean
    @ConditionalOnMissingBean(CharacterEncodingFilter.class)// 当容器中没有这个Bean
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
        return filter;
    }

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

    private static class LocaleCharsetMappingsCustomizer
            implements EmbeddedServletContainerCustomizer, Ordered {

        private final HttpEncodingProperties properties;

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

        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            if (this.properties.getMapping() != null) {
                container.setLocaleCharsetMappings(this.properties.getMapping());
            }
        }

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

    }

}

你可能感兴趣的:(Spring Boot 运行原理 - 实例分析(HttpEncodingAutoConfiguration))