Spring Boot技术内幕:架构设计与实现原理
上QQ阅读APP看书,第一时间看更新

2.5 实例解析

在了解整个Spring Boot的运作原理之后,我们以Spring Boot内置的http编码功能为例,分析一下整个自动配置的过程。

在常规的Web项目中该配置位于web.xml,通过<filter>来进行配置。


<filter>  
    <filter-name>encodingFilter</filter-name>  
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter
    </filter-class>  
    <init-param>  
        <param-name>encoding</param-name>  
        <param-value>UTF-8</param-value>  
    </init-param>  
    <init-param>  
        <param-name>forceEncoding</param-name>  
        <param-value>true</param-value>  
    </init-param>  
</filter>

而在Spring Boot中通过内置的HttpEncodingAutoConfiguration来完成这一功能。下面我们具体分析一下该功能都涉及哪些配置和实现。

根据前面讲的操作流程,我们先来看一下META-INF/spring.factories中对该自动配置的注册。


# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
...
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
...

当完成注册之后,在加载的过程中会使用元数据的配置进行过滤,对应的配置内容在META-INF/spring-autoconfigure-metadata.properties文件中。


org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration.ConditionalOnClass=org.springframework.web.filter.CharacterEncodingFilter

在过滤的过程中要判断自动配置类HttpEncodingAutoConfiguration是否被@ConditionalOnClass注解,源代码如下。


@Configuration
@EnableConfigurationProperties(HttpProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled",
        matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

    private final HttpProperties.Encoding properties;

    public HttpEncodingAutoConfiguration(HttpProperties properties) {
        this.properties = properties.getEncoding();
    }

    @Bean
    @ConditionalOnMissingBean
    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;
    }
    ...
    }

很明显,它被@ConditionalOnClass注解,并且指定实例化的条件为类路径下必须有CharacterEncodingFilter存在。再看一下该类的其他注解。

·@Configuration:指定该类作为配置项来进行实例化操作。

·@EnableConfigurationProperties:参数为HttpProperties.class,开启属性注入,会将参数中的HttpProperties注入该类。

·@ConditionalOnWebApplication:参数为Type.SERVLET,说明该类只有在基于servlet的Web应用中才会被实例化。

·@ConditionalOnClass:参数为CharacterEncodingFilter.class,只有该参数存在,才会被实例化。

·@ConditionalOnProperty:指定配置文件内spring.http.encoding对应的值,如果为enabled才会进行实例化,没有配置则默认为true。

·@ConditionalOnMissingBean:注释于方法上,与@Bean配合,当容器中没有该Bean的实例化对象时才会进行实例化。

其中HttpProperties类的属性值对应着application.yml或application.properties中的配置,通过注解@ConfigurationProperties(prefix="spring.http")实现的属性注入。关于属性注入,后面章节会详细讲解,这里我们先看一下源代码和对应的配置文件参数。


@ConfigurationProperties(prefix = "spring.http")
public class HttpProperties {
    ...
    public static class Encoding {
        public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
        private Charset charset = DEFAULT_CHARSET;
        private Boolean force;
        private Boolean forceRequest;
        private Boolean forceResponse;
        private Map<Locale, Charset> mapping;
    ...
    }
}

而在application.properties中,我们会进行如下对应配置:


spring.http.encoding.force=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.force-request=true
...