SpringBoot進階之道-自動裝配

SpringBoot的自動裝配是拆箱即用的基礎,也是爲服務化的前提。java

1、自動裝配的過程

1.1 @SpringBootApplication

前面一章我講解過了《SpringBoot進階之道-@SpringBootApplication》。咱們知道@SpringBootApplication包含了@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan。spring

1.2 @EnableAutoConfiguration

在上一章我講解過《SpringBoot進階之道-@Enable模塊驅動》,這種@Enabelxx的註解是開啓某一項功能的註解,其原理是藉助@Import,將全部符合自動配置條件的bean定義加載到IOC容器。具體的能夠去看看。數組

那麼@EnableAutoConfiguration這個註解會開啓springboot自動裝配功能。直白的說,Spring會試圖在你的classpath下找到全部配置的Bean而後進行裝配。咱們以springboot2.x源碼爲例: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 {};
}
複製代碼

從源碼咱們得知,關鍵是@Import({AutoConfigurationImportSelector.class}),藉助AutoConfigurationImportSelector,@EnableAutoConfiguration能夠幫助springboot應用將全部符合條件的@Configuration配置都加載到當前SpringBoot建立並使用的ioc容器。那麼我爲何這麼說呢?咱們看下AutoConfigurationImportSelector源碼:bash

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方法:post

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以下:this

# 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容器。因此,之前咱們須要本身配置的東西,自動配置類都幫咱們完成了,是否是很嗨~~~spa

相關文章
相關標籤/搜索