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方法的处理过程,详细参见:。

 

 

 

©️2020 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值