zoukankan      html  css  js  c++  java
  • springboot的自动配置

    1. 起因

    ​ 使用springboot也有些时间,一直很好奇它如何做到自动配置的,所以查阅了相关资料并且学习了相关内容,才写了这篇文章。

    2. 分析

    ​ ①第一步我们从它的启动配置类(XxxApplication)收起,我们进入到他的@SpringBootApplication注解。
    在这里插入图片描述

    ​ ②我们可以看到如下代码,由于我们需要找到导致它自动配置的,所以锁定了@EnableAutoConfiguration注解,那么就可以进入这个注解。

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(
        excludeFilters = {@Filter(
        type = FilterType.CUSTOM,
        classes = {TypeExcludeFilter.class}
    ), @Filter(
        type = FilterType.CUSTOM,
        classes = {AutoConfigurationExcludeFilter.class}
    )}
    )
    public @interface SpringBootApplication {
        @AliasFor(
            annotation = EnableAutoConfiguration.class
        )
        Class<?>[] exclude() default {};
    
        @AliasFor(
            annotation = EnableAutoConfiguration.class
        )
        String[] excludeName() default {};
    
        @AliasFor(
            annotation = ComponentScan.class,
            attribute = "basePackages"
        )
        String[] scanBasePackages() default {};
    
        @AliasFor(
            annotation = ComponentScan.class,
            attribute = "basePackageClasses"
        )
        Class<?>[] scanBasePackageClasses() default {};
    }
    

    在这里插入图片描述

    ​ ③ 我们看到了如下代码,由于这是一个接口,而它的实现类我们又不好确定,所以我们只好从注解入手,由于@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited等都是元注解,我们可以从@AutoConfigurationPackage,@Import({AutoConfigurationImportSelector.class})中找到我们想要的,根据它的中文意思我们可以从@Import({AutoConfigurationImportSelector.class})(自动有选择的导入配置)出发,毕竟不是所有的配置都会都如,而导入那些配置根据项目中使用了那些starter决定。
    在这里插入图片描述

    ​ ④点入第三步提到的注解,进入这个类根据方法名我们可以猜测是和这个方法相关,通过阅读这个代码,我们可以猜测是和getAutoConfigurationEntry这个方法有关,所以不妨点进去。

     public String[] selectImports(AnnotationMetadata annotationMetadata) {
            if (!this.isEnabled(annotationMetadata)) {
                return NO_IMPORTS;
            } else {
                AutoConfigurationMetadata autoConfigurationMetadata = 		 AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
                AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
                return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
            }
        }
    

    ​ ⑤由于我们需要的配置Config,所以大致可以断定是和这个代码有关联List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);,所以不妨进到这个getCandidateConfigurations方法中去。

    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
            if (!this.isEnabled(annotationMetadata)) {
                return EMPTY_ENTRY;
            } else {
                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 new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
            }
        }
    

    ​ ⑥经过第五步,我们可以看到如下代码

     protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
            List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
        }
    

    不妨看这部分代码,List configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());,它的意思是一个加载器通过加载某个工厂获得配置的List,因此我们在进入到这个的实现是没有必要的,可以从参数考虑,所以锁定在第一个参数,点进入可以看到如下代码。

    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
            return EnableAutoConfiguration.class;
        }
    

    看到这里可能还是会疑惑?为啥就自动配置了,其实我们这个方法(loadFactoryNames)是从一个配置文件中读取内容,它的键是EnableAutoConfiguration,而这个配置文件是在如图所示的文件中。

    在这里插入图片描述
    在这里插入图片描述

    ⑥打开上述文件,根据上一步的键找它的值,如图就是springboot配置类,那么项目启动时是不是所有的配置都起作用吗?不妨进入到某个配置类查看即可。如图所示的@ConditionalOnMissingBean注解表示项目的容器是否有这个bean,如果没有这个配置类就不会其作用,另外我们只要在仔细看这个类首先进行了初始化,之后它会从配置文件(application.xml或者application.yml)中获取值。
    在这里插入图片描述

    注:如有错误,欢迎指出。

    作者:pavi

    出处:http://www.cnblogs.com/pavi/

    本文版权归作者和博客园所有,欢迎转载。转载请在留言板处留言给我,且在文章标明原文链接,谢谢!

    如果您觉得本篇博文对您有所收获,觉得我还算用心,请点击右下角的 [推荐],谢谢!

  • 相关阅读:
    E. XOR and Favorite Number (莫队板子题)
    bzoj 2038: [2009国家集训队]小Z的袜子(hose)
    世风日下的哗啦啦族I (简单分块模板)
    Turtles (非纯分块)
    楼房重建
    智商问题
    A
    51 Nod 1640 天气晴朗的魔法( Kruskall )
    后缀数组
    51nod 1562 玻璃切割 (set)
  • 原文地址:https://www.cnblogs.com/pavi/p/12437314.html
Copyright © 2011-2022 走看看