Spring Boot源碼(五) - 自動裝配(上)

目錄

1、@SpringBootConfiguration

2、@ComponentScan

3、@ConfigurationPropertiesScan

4、@EnableAutoConfiguration

1)、@AutoConfigurationPackage

2)、AutoConfigurationImportSelector


    按照SpringApplication的run方法執行流程,在refreshContext時候會調用refresh方法,其中會在ConfigurationClassPostProcessor中處理@Import,ImportSelector等(詳細可以參見:SpringIoc源碼(十)- ApplicationContext(六)- refresh(ConfigurationClassPostProcessor上)Spring源碼-ImportSelector實現分析)。而自動裝配則是通過@SpringBootApplication註解實現,其註解中@ComponentScan或@Import(AutoConfigurationImportSelector.class)等都是ConfigurationClassPostProcessor進行處理的。所以按照Spring Boot啓動的執行時機,在這個地方開始分析自動裝配。

    自動裝配就是@EnableAutoConfiguration註解,只是我們一般會直接使用@SpringBootApplication。Spring 要求是將該註解放在一個可以掃描的@Component上即可(之前分析過,解析@Component時,會將其上面的註解進行處理),所以我們一般會放到main方法啓動類上,前面(上一篇博客)分析過會將main方法啓動類進行註冊BeanDefinition。則會將其上面的註解進行解析和處理。

@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) })
@ConfigurationPropertiesScan
public @interface SpringBootApplication {
    // 省略字段
}

1、@SpringBootConfiguration

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

    @AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;
}

    個人認爲之前是需要將@SpringBootApplication放在能註冊成@Component的類上,而現在自己本身就是一個@Component,再加上下面的@EnableAutoConfiguration本身會將該註解所在類的包進行ComponentScan處理(可以參見:SpringIoc源碼(十一)- ApplicationContext(七)- refresh(ConfigurationClassPostProcessor下))。

2、@ComponentScan

@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

    進行@ComponentScan處理,只是需要排除掉TypeExcludeFilter和AutoConfigurationExcludeFilter。

3、@ConfigurationPropertiesScan

    @ConfigurationPropertiesScan是Spring Boot新增的註解,看字面意思是掃描所有的@ConfigurationProperties註解,並進行加載。具體看看註解的定義:

// 省去元註解
@Import(ConfigurationPropertiesScanRegistrar.class)
@EnableConfigurationProperties
public @interface ConfigurationPropertiesScan {

    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};
}

   具體實現過程參見:。

 

4、@EnableAutoConfiguration

// 省略元註解
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

    通過註解我們可以配置不進行注入的名稱數組或者類數組,當讓默認情況下,@EnableAutoConfiguration被標記在@SpringBootApplication上使用,則該值都爲空。

    再看@AutoConfigurationPackage,應該是將該文件類所在目錄的包下面的@Component註冊成Bean。@Import分析過會將AutoConfigurationImportSelector註冊成一個Bean。

1)、@AutoConfigurationPackage

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

}

     通過@import將註冊成一個Bean,繼續看其結構:

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        register(registry, new PackageImport(metadata).getPackageName());
    }

    @Override
    public Set<Object> determineImports(AnnotationMetadata metadata) {
        return Collections.singleton(new PackageImport(metadata));
    }
}

    DeterminableImports是Spring Boot的接口,先不進行分析。之前分析過 ImportBeanDefinitionRegistrar 回調,會將BeanDefinitionRegistry(其實當前回傳的是AbstractApplicationContext)傳回來,進行進行BeanDefinition的注入,並且在refresh的最後階段將單利懶加載的Bean進行getBean操作全部初始化。回調時機發生在refresh的(詳細可以參考:SpringIoc源碼(十)- ApplicationContext(六)- refresh(ConfigurationClassPostProcessor上)):

AbstractApplicationContext # invokeBeanFactoryPostProcessors

PostProcessorRegistrationDelegate # invokeBeanFactoryPostProcessors

                                                          # invokeBeanDefinitionRegistryPostProcessors

ConfigurationClassPostProcessor # postProcessBeanDefinitionRegistry

                                                       # processConfigBeanDefinitions

ConfigurationClassBeanDefinitionReader # loadBeanDefinitions

                                                                  # loadBeanDefinitionsForConfigurationClass

                                                                  # loadBeanDefinitionsFromRegistrars

 

    知道了執行時機,並且AutoConfigurationPackages.Registrar回調的時候會回傳對應的AnnotationMetadata(註解元數據)。

new PackageImport(metadata).getPackageName()
PackageImport(AnnotationMetadata metadata) {
    this.packageName = ClassUtils.getPackageName(metadata.getClassName());
}

    比較清楚,拿到@SpringBootApplication或@EnableAutoConfiguration註解所在類的包名,調用註冊方法:

public static void register(BeanDefinitionRegistry registry, String... packageNames) {
    // BEAN = AutoConfigurationPackages.class.getName();
    if (registry.containsBeanDefinition(BEAN)) {
        BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
        ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
        constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
    }
    else {
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(BasePackages.class);
        beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registry.registerBeanDefinition(BEAN, beanDefinition);
    }
}

    先判斷AutoConfigurationPackages本身是否有註冊成BeanDefinition(可能存在用戶自定義註冊等情況,考慮太全了)。如果是則在BeanDefinition上直接添加包信息,否則new 一個新的GenericBeanDefinition,再添加包信息。則會在refresh的最後階段依賴對所有單利非懶加載的Bean進行依賴注入。

 

2)、AutoConfigurationImportSelector

   AutoConfigurationImportSelector 分爲兩部分進行分析,

首先是Spring對DeferredImportSelector的調用時機和解析處理過程(怎樣註冊成Bean的),參見:Spring源碼 - DeferredImportSelector實現分析

第二部分是AutoConfigurationImportSelector的process和selectImports方法的處理過程,詳細參見:。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章