SpringBoot 自动装配机制究竟是怎么实现的

主启动类

@SpringBootApplication

用来标准主程序类,说明这是一个springboot应用,点进去之后可以发现还有很多其他注解。

@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}
)}
)

@ComponentScan

这个注解在Spring中非常重要,它对应XML配置中的元素。主要作用就是用来自动扫描并加载符合条件的组件或者bean,将这个bean定义加载到IOC容器中。

@SpringBootConfiguration

SpringBoot的配置类,标注在某个类上面,表明这是一个SpringBoot的配置类,点进去这个注解可以继续查看

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}

@Component
public @interface Configuration {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}

这里的@Configuration, 说明这是一个配置类,配置类就是对应Spring的XML文,@Component说明启动类本身也是Spring的一个组件,负责启动应用!

@EnableAutoConfiguration

开启自动配置功能,实现SpringBoot帮我们自动配置,点进注解可以继续查看

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

@AutoConfigurationPackge 自动配置包

@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}

@import 给容器导入一个组件,Registrar.class作用就是将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器.
@Import({AutoConfigurationImportSelector.class}) 自动配置导入选择器,在Springboot应用启动过程中会使用ConfigurationClassParser分析配置类,如果发现注解中存在@Import(ImportSelector)的情况,就会创建一个相应的importSelector的对象,并调用其中的selectImport方法,AutoConfigurationImportSelector.class就属于这种情况,所以以ConfigurationClassParser会实例化一个AutoConfigurationImportSele并调用它的 selectImports() 方法。

    // selectImports 的具体执行逻辑
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        try {
            // 从配置文件中加载 AutoConfigurationMetadata
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                    .loadMetadata(this.beanClassLoader);
            AnnotationAttributes attributes = getAttributes(annotationMetadata);
            // 获取所有候选配置类EnableAutoConfiguration
            // 使用了内部工具使用SpringFactoriesLoader,查找classpath上所有jar包中的
            // META-INF\spring.factories,找出其中key为
            // org.springframework.boot.autoconfigure.EnableAutoConfiguration 
            // 的属性定义的工厂类名称。
            // 虽然参数有annotationMetadata,attributes,但在 AutoConfigurationImportSelector 的
            // 实现 getCandidateConfigurations()中,这两个参数并未使用
            List<String> configurations = getCandidateConfigurations(annotationMetadata,
                    attributes);
            // 去重                   
            configurations = removeDuplicates(configurations);
            // 排序 : 先按字典序,再按order属性,再考虑注解  @AutoConfigureBefore @AutoConfigureAfter
            configurations = sort(configurations, autoConfigurationMetadata);
            // 应用 exclusion 属性
            Set<String> exclusions = getExclusions(annotationMetadata, attributes);
            checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            // 应用过滤器AutoConfigurationImportFilter,
            // 对于 spring boot autoconfigure,定义了一个需要被应用的过滤器 :
            // org.springframework.boot.autoconfigure.condition.OnClassCondition,
            // 此过滤器检查候选配置类上的注解@ConditionalOnClass,如果要求的类在classpath
            // 中不存在,则这个候选配置类会被排除掉
            configurations = filter(configurations, autoConfigurationMetadata);
            // 现在已经找到所有需要被应用的候选配置类
            // 广播事件 AutoConfigurationImportEvent
            fireAutoConfigurationImportEvents(configurations, exclusions);
            return configurations.toArray(new String[configurations.size()]);
        }
        catch (IOException ex) {
            throw new IllegalStateException(ex);
        }
    }
    /**
     * Return the auto-configuration class names that should be considered. By default
     * this method will load candidates using SpringFactoriesLoader with
     * getSpringFactoriesLoaderFactoryClass().
     * @param metadata the source metadata
     * @param attributes the 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;
    }
 
    /**
     * Return the class used by SpringFactoriesLoader to load configuration
     * candidates.
     * @return the factory class
     */
    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
        return EnableAutoConfiguration.class;
    }   
    /**
      * 根据autoConfigurationMetadata信息对候选配置类configurations进行过滤
      **/
    private List<String> filter(List<String> configurations,
            AutoConfigurationMetadata autoConfigurationMetadata) {
        long startTime = System.nanoTime();
        String[] candidates = configurations.toArray(new String[configurations.size()]);
        // 记录候选配置类是否需要被排除,skip为true表示需要被排除,全部初始化为false,不需要被排除
        boolean[] skip = new boolean[candidates.length];
        // 记录候选配置类中是否有任何一个候选配置类被忽略,初始化为false
        boolean skipped = false;
        // 获取AutoConfigurationImportFilter并逐个应用过滤
        for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
            // 对过滤器注入其需要Aware的信息
            invokeAwareMethods(filter);
            // 使用此过滤器检查候选配置类跟autoConfigurationMetadata的匹配情况
            boolean[] match = filter.match(candidates, autoConfigurationMetadata);
            for (int i = 0; i < match.length; i++) {
                if (!match[i]) {
                // 如果有某个候选配置类不符合当前过滤器,将其标记为需要被排除,
                // 并且将 skipped设置为true,表示发现了某个候选配置类需要被排除
                    skip[i] = true;
                    skipped = true;
                }
            }
        }
        if (!skipped) {
        // 如果所有的候选配置类都不需要被排除,则直接返回外部参数提供的候选配置类集合
            return configurations;
        }
        // 逻辑走到这里因为skipped为true,表明上面的的过滤器应用逻辑中发现了某些候选配置类
        // 需要被排除,这里排除那些需要被排除的候选配置类,将那些不需要被排除的候选配置类组成
        // 一个新的集合返回给调用者
        List<String> result = new ArrayList<String>(candidates.length);
        for (int i = 0; i < candidates.length; i++) {
            if (!skip[i]) {
                result.add(candidates[i]);
            }
        }
        if (logger.isTraceEnabled()) {
            int numberFiltered = configurations.size() - result.size();
            logger.trace("Filtered " + numberFiltered + " auto configuration class in "
                    + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)
                    + " ms");
        }
        return new ArrayList<String>(result);
    }   
    /**
      * 使用内部工具 SpringFactoriesLoader,查找classpath上所有jar包中的
      * META-INF\spring.factories,找出其中key为
      * org.springframework.boot.autoconfigure.AutoConfigurationImportFilter 
      * 的属性定义的过滤器类并实例化。
      * AutoConfigurationImportFilter过滤器可以被注册到 spring.factories用于对自动配置类
      * 做一些限制,在这些自动配置类的字节码被读取之前做快速排除处理。
      * spring boot autoconfigure 缺省注册了一个 AutoConfigurationImportFilter :
      * org.springframework.boot.autoconfigure.condition.OnClassCondition
    **/
    protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
        return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,
                this.beanClassLoader);
    }   
posted @ 2022-03-31 10:35  YoungerWb  阅读(176)  评论(0)    收藏  举报