Spring Boot 回顾(三):自动装配原理解析

450 阅读2分钟

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战

前言

之前的文章中,我们实现Spring Boot的下自定义注解功能,想必对于Spring Boot大家都应该很了解。在项目的启动类上,我们有注意到@SpringBootApplication这个注解,之前文章里也有介绍的其实它是由@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan这三个注解组成的。@ComponentScan介绍过了,它的作用是指定扫描包的范围;@SpringBootConfiguration这个注解我们之后文章中再来详细介绍。本文主要重点深入@EnableAutoConfiguration这个注解,看看Spring Boot的自动装配是如何实现的。

@EnableAutoConfiguration注解

首先我们看下@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这个类,接下来我们再进入看下这个类的源码

image.png 首先该类实现了DeferredImportSelector接口,而这个接口继承了ImportSelector image.png 可以看到它的作用就是为了导入@Configuration的配置项,而DeferredImportSelector是延期导入,当所有的@Configuration都处理过后才会执行。好了,我们再回过头看下AutoConfigurationImportSelector类的selectImports方法:

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());
    }
}

首先if (!this.isEnabled(annotationMetadata))这里判断是否进行自动装配,如果是的话那么通过loadMetadata方法去META-INF/spring-autoconfigure-metadata.properties读取元数据与元数据的相关属性 image.png 接着我们看getCandidateConfigurations方法,它会读取META-INF/spring.factories下的EnableAutoConfiguration的配置,紧接着在进行排除与过滤,为什么要过滤呢?原因是很多的@Configuration其实是依托于其他的框架来加载的,如果当前的classpath环境下没有相关联的依赖,则意味着这些类没必要进行加载,所以,通过这种条件过滤可以有效的减少@configuration类的数量从而降低SpringBoot的启动时间。 之后我们得到需要装配的类。最后让所有配置在META-INF/spring.factories下的AutoConfigurationImportListener执行AutoConfigurationImportEvent事件。

image.png

image.png 至此,我们差不多看到了自动装配的整个流程。

总结

其实在getCandidateConfigurations方法中,我们有看到熟悉的SpringFactoriesLoader,因此自动装配还是利用了SpringFactoriesLoader来加载META-INF/spring.factoires文件里所有配置的EnableAutoConfgruation,它会经过exclude和filter等操作,最终确定要装配的类。