SpringBoot初学习——自动配置原理的简单介绍

一.前言
我在这系列的第一篇文章中已经说过,SpringBoot通过@Import({AutoConfigurationImportSelector.class})使得其在启动的时候,就自动注入了很多的配置类。那么这些配置类是如何被加载到我们的容器中的呢?下面我们来举个例子HttpEncodingAutoConfiguration这个自动配置类。

二.具体的介绍
1.首先我们看看这个类的源码:

@Configuration(
    proxyBeanMethods = false
)
@EnableConfigurationProperties({HttpProperties.class})
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class})
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
    private final 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(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
        return filter;
    }

2.我们对于代码进行逐个解析
2.1.1.@EnableConfigurationProperties({HttpProperties.class}):启动指定类的ConfigurationProperties功能。将配置文件中对应的值和HttpProperties绑定起来;并把HttpProperties加入到ioc容器中,我们看一下HttpProPerties

@ConfigurationProperties(
    prefix = "spring.http"
)
public class HttpProperties {
    private boolean logRequestDetails;
    private final HttpProperties.Encoding encoding = new HttpProperties.Encoding();

    public HttpProperties() {
    }

这里我们可以看到,该类通过@ConfigurationProperties 注解,表明了该类的成员变量是通过配置文件注入。(具体可以看看@ConfigurationProperties作用)——所以修改了时候,直接在配置文件修改。
继续看回HttpEncodingAutoConfiguration 类

  private final Encoding properties;

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

我们可以看到构造方法的入参实际是来着我们上面讲的绑定参数,接着将值传递给HttpEncodingAutoConfiguration 类的Encoding properties

2.2.条件过滤,根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效; 判断当前应用是否是web应用,如果是,当前配置类生效

@ConditionalOnWebApplication(
    type = Type.SERVLET
)

2.3.条件过滤:判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;

@ConditionalOnClass({CharacterEncodingFilter.class})

2.4.判断配置文件中是否存在某个配置 spring.http.encoding.enabled;如果不存在,判断也是成立的
matchIfMissing :即使我们配置文件中不配置spring.http.encoding.enabled=true,也是默认生效的

@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)

2.5.这里还要讲解点代码:

  @Bean
    @ConditionalOnMissingBean
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
        return filter;
    }

@Bean 表示将返回的类注入到容器中,然后我们可以发现,该方法中的属性都是来自我们的 Encoding properties; 。下面的bean也是一样

二.因此我们可以有个小结(其他xxxxAutoAutoConfiguration类也是这种模式):

对于HttpEncodingAutoConfiguration这个类,在通过了各类条件(@ConditionalOnWebApplication,@ConditionalOnClass,@ConditionalOnProperty)判断以后,再通过属性的绑定(@EnableConfigurationProperties({HttpProperties.class})),最终加载到容器中(@Bean) ,其相关属性可以通过配置文件进行修改,例如:

spring.http.encoding.charset=GBK
spring.http.logRequestDetails=false

具体对应HttpProperties这个类

@ConfigurationProperties(
    prefix = "spring.http"
)
public class HttpProperties {
    private boolean logRequestDetails;
    private final HttpProperties.Encoding encoding = new HttpProperties.Encoding();

    public HttpProperties() {
    }

    public boolean isLogRequestDetails() {
        return this.logRequestDetails;
    }

    public void setLogRequestDetails(boolean logRequestDetails) {
        this.logRequestDetails = logRequestDetails;
    }

    public HttpProperties.Encoding getEncoding() {
        return this.encoding;
    }

    public static class Encoding {
        public static final Charset DEFAULT_CHARSET;
        private Charset charset;
        private Boolean force;
        private Boolean forceRequest;
        private Boolean forceResponse;
        private Map mapping;

三.小扩展
上面我们说了,自动配置的生效需要经过很多条件判断@xxConditionaxx.那么我们如何知道,在SpringBoot启动的时候,哪些自动配置生效了?哪些没有生效?
我们通过在配置文件加上 debug=true
然后我就可以再控制台看到打印如下:

=========================
AUTO-CONFIGURATION REPORT
=========================


Positive matches:(自动配置类启用的)
-----------------

   DispatcherServletAutoConfiguration matched:
      - @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
      - @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition)
        
    
Negative matches:(没有启动,没有匹配成功的自动配置类)
-----------------

   ActiveMQAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)

   AopAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required classes 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice' (OnClassCondition)

你可能感兴趣的:(SpringBoot)