SpringBoot的运行原理之自动配置

SpringBoot的核心就是自动配置,自动配置又是基于条件判断来配置Bean。关于自动配置的源码在spring-boot-autoconfigure-2.0.3.RELEASE.jar,在这里看:
这里写图片描述

这里写图片描述


查看配置报告
在配置文件中加入如下配置,查看当前已开启和未开启的自动配置报告:

#查看当前项目中已启用和未启用的自动配置的报告
debug: true

启动项目

已开启的配置:
这里写图片描述
未开启的配置:
这里写图片描述


SpringBoot运行原理
先看@SpringBootApplication

  • @SpringBootConfiguration:标记当前类为配置类
  • @EnableAutoConfiguration:开启自动配置
  • @ComponentScan:扫描主类所在的同级包以及下级包里的Bean

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

关键是@Import(AutoConfigurationImportSelector.class)导入的配置功能,
AutoConfigurationImportSelector中的方法getCandidateConfigurations,得到待配置的class的类名集合

/**
     * Return the auto-configuration class names that should be considered. By default
     * this method will load candidates using {@link SpringFactoriesLoader} with
     * {@link #getSpringFactoriesLoaderFactoryClass()}.
     * @param metadata the source metadata
     * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
     * attributes}
     * @return a list of candidate configurations
     */
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
            AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
                getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
        Assert.notEmpty(configurations,
                "No auto configuration classes found in META-INF/spring.factories. If you "
                        + "are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

通过SpringFactoriesLoader.loadFactoryNames()方法扫描META-INF/spring.factories文件
这里写图片描述
这文件列出了哪些需要自动配置。
随便打开一个配置类,例如:
这里写图片描述
都能看到各种各样的条件判断注解,满足条件时就加载这个Bean。
此类的条件注解是:@ConditionalOnProperty

  • @ConditionalOnBean:当容器里有指定Bean的条件下
  • @ConditionalOnClass:当类路径下有指定的类的条件下
  • @ConditionalOnExpression:基于SpEL表达式作为判断条件
  • @ConditionalOnJava:基于JVM版本作为判断条件
  • @ConditionalOnJndi:在JNDI存在的条件下查找指定的位置
  • @ConditionalOnMissingBean:当容器里没有指定Bean的情况下
  • @ConditionalOnMissingClass:当容器里没有指定类的情况下
  • @ConditionalOnWebApplication:当前项目时Web项目的条件下
  • @ConditionalOnNotWebApplication:当前项目不是Web项目的条件下
  • @ConditionalOnProperty:指定的属性是否有指定的值
  • @ConditionalOnResource:类路径是否有指定的值
  • @ConditionalOnOnSingleCandidate:当指定Bean在容器中只有一个,或者有多个但是指定首选的Bean

这些注解都组合了@Conditional注解,只是使用了不同的条件。


通过实例,http编码的默认配置来讲解配置流程
双击shift搜索HttpEncodingProperties,这个类型安全的参数绑定的类就为自动配置http默认编码时提供配置参数。

@ConfigurationProperties(prefix = "spring.http.encoding")
public class HttpEncodingProperties {

    public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

    /**
     * Charset of HTTP requests and responses. Added to the "Content-Type" header if not
     * set explicitly.
     */
    private Charset charset = DEFAULT_CHARSET;//默认编码方式UTF-8

    /**
     * Whether to force the encoding to the configured charset on HTTP requests and
     * responses.
     */
    private Boolean force;

    /**
     * Whether to force the encoding to the configured charset on HTTP requests. Defaults
     * to true when "force" has not been specified.
     */
    private Boolean forceRequest;

    /**
     * Whether to force the encoding to the configured charset on HTTP responses.
     */
    private Boolean forceResponse;

    /**
     * Locale in which to encode mapping.
     */
    private Map<Locale, Charset> mapping;
    省略set/get
}
  • @ConfigurationProperties(prefix = “spring.http.encoding”):application配置文件配置时前缀是”spring.http.encoding”

双击shift搜索HttpEncodingAutoConfiguration http编码自动配置类,只截取部分代码

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

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

    private final HttpEncodingProperties properties;

    public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
        this.properties = properties;
    }
    @Bean//设置Bean   CharacterEncodingFilter 
    @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;
    }
}
  • @Configuration:标明为配置类
  • @EnableConfigurationProperties(HttpEncodingProperties.class)声明开启属性注入
  • @ConditionalOnClass(CharacterEncodingFilter.class)当CharacterEncodingFilter在类路径的条件下
  • @ConditionalOnProperty(prefix = “spring.http.encoding”, value = “enabled”, matchIfMissing = true)当spring.http.encoding=enabled的情况下,如果没有设置则默认为true,即条件符合
  • @ConditionalOnMissingBean当容器中没有这个Bean时新建Bean

SpringBoot的核心,自动配置的流程大概就是这个样子,下一篇演示创建自己的starter pom。
SpringBoot核心自动配置之创建自己的starter pom maven依赖包


这里写图片描述

猜你喜欢

转载自blog.csdn.net/Axela30W/article/details/80803885