SpringBoot进阶之道-自动装配

Posted 草莓君_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot进阶之道-自动装配相关的知识,希望对你有一定的参考价值。

SpringBoot的自动装配是拆箱即用的基础,也是为服务化的前提。

一、自动装配的过程

1.1 @SpringBootApplication

前面一章我讲解过了《SpringBoot进阶之道-@SpringBootApplication》。我们知道@SpringBootApplication包含了@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan。

1.2 @EnableAutoConfiguration

在上一章我讲解过《SpringBoot进阶之道-@Enable模块驱动》,这种@Enabelxx的注解是开启某一项功能的注解,其原理是借助@Import,将所有符合自动配置条件的bean定义加载到IOC容器。具体的可以去看看。

那么@EnableAutoConfiguration这个注解会开启springboot自动装配功能。直白的说,Spring会试图在你的classpath下找到所有配置的Bean然后进行装配。我们以springboot2.x源码为例:

@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,@EnableAutoConfiguration可以帮助springboot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的ioc容器。那么我为什么这么说呢?我们看下AutoConfigurationImportSelector源码:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    ...
    public AutoConfigurationImportSelector() {
    }
}

该类实现了DeferredImportSelector接口,而DeferredImportSelector是继承了ImportSelector:

public interface ImportSelector {
    String[] selectImports(AnnotationMetadata var1);
}

ImportSelector接口主要是为了导入@Configuration的配置项,而DeferredImportSelector是延期导入,当所有的@Configuration都处理过后才会执行。
我们看看AutoConfigurationImportSelector实现的selectImports方法:

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 判断是否进行自动装配
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            //1加载META-INF/spring-autoconfigure-metadata.properties文件
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            //2获取注解的属性及其值(PS:注解指的是@EnableAutoConfiguration注解)
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            //3.在classpath下所有的META-INF/spring.factories文件中查找org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,并将其封装到一个List中返回
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            //4.对上一步返回的List中的元素去重、排序
            configurations = this.removeDuplicates(configurations);
            //5.依据第2步中获取的属性值排除一些特定的类
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            //6.对上一步中所得到的List进行过滤,过滤的依据是条件匹配。这里用到的过滤器是
            //org.springframework.boot.autoconfigure.condition.OnClassCondition最终返回的是一个ConditionOutcome[]数组。
            //(PS:很多类都是依赖于其它的类的,当有某个类时才会装配,所以这次过滤的就是根据是否有某个
            //class进而决定是否装配的。这些类所依赖的类都写在META-INF/spring-autoconfigure-metadata.properties文件里)
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.filter(configurations, autoConfigurationMetadata);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }
     ....
    public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
        return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties");
    }
}

从上面的源码得知,该方法先判断是否进行自动装配,然后从META-INF/spring-autoconfigure-metadata.properties读取元数据与元数据的相关属性,然后调用getCandidateConfigurations方法:

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

这个时候我们看到个Spring框架原有的一个工具类SpringFactoriesLoader,其主要的工作是从指定的META-INF/spring.factories加载配置,即根据@EnableAutoConfiguration的完整类名"org.springframework.boot.autoconfigure.EnableAutoConfiguration"作为查找的Key,获取对应的配置,通过反射得到对应的一组@Configuration类。spring.factories中EnableAutoConfiguration如下:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\\
....

总结:自动装配就是利用SpringFactoriesLoader从classpath中搜索所有的META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的配置项通过反射实例化为标注了@Configuration的JavaConfig形式的配置类,然后汇总并加载到ioc容器。所以,以前我们需要自己配置的东西,自动配置类都帮我们完成了,是不是很嗨~~~

以上是关于SpringBoot进阶之道-自动装配的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot进阶之道-Starter机制

SpringBoot进阶之道-@Enable模块驱动

SpringBoot学习探究Springboot自动装配

SpringBoot自动装配流程源码分析

深入理解SpringBoot之自动装配

SpringBoot自动装配原理详细讲解(清楚 明白)