理解Spring boot的自动装配

Spring boot的自动装配可以从官方文档得出答案:Spring boot自动装配的特性可以由@EnableAutoConfiguration来激活。@SpringBootApplication又是包含以下三个注解:@SpringBootConfiguration、@ComponentScan、@EnableAutoConfiguration。因此@SpringBootApplication也是可以进行自动装配的。(从这里可以看出@SpringBootApplication注解不是spring boot项目的必备注解,可以通过下面的案例进行证实)

@EnableAutoConfiguration
public class WmGameApplicationTests {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(ConfigBean.class);
        /*String [] beanNames=annotationConfigApplicationContext.getBeanNamesForType(Color.class);
        Map mapBean=  annotationConfigApplicationContext.getBeansOfType(Color.class);
        for(String item:beanNames){
            System.out.println("bean名称:"+item+"--- 输出bean对象:"+mapBean.get(item));
        }*/
        System.out.println("当前spring应用上下文所在注册bean名称");
        Stream.of(annotationConfigApplicationContext.getBeanDefinitionNames())
                .map(name -> "\t" + name)
                .forEach(System.out::println);
        annotationConfigApplicationContext.close();
    }

}

输出结果为:

当前spring应用上下文所在注册bean名称
	org.springframework.context.annotation.internalConfigurationAnnotationProcessor
	org.springframework.context.annotation.internalAutowiredAnnotationProcessor
	org.springframework.context.annotation.internalRequiredAnnotationProcessor
	org.springframework.context.annotation.internalCommonAnnotationProcessor
	org.springframework.context.event.internalEventListenerProcessor
	org.springframework.context.event.internalEventListenerFactory

只是@SpringBootApplication可以减少多注解带来的配置成本,如配置@SpringBootApplication的scanBasePackages等同于@ComponentScan#basePackages 

一、替换自动装配

在开发人员在任意一处定义配置类,从而可以覆盖自动装配的组件。如:通过自定义的dataSource替换默认的数据源。

二、失效自动装配

在注解@EnableAutoConfiguration中可以看到,提供了几个参数:exclude()和excludeName()。

三、spring boot的自动装配原理

依照@Enable模块驱动模式,@EnableAutoConfiguration的实现肯定是"@import"importSelector、importBeanDefinitionRegirstar的实现类。查看源码可以知道这个实现类是:AutoConfigurationImportSelector

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

仔细跟踪AutoConfigurationImportSelector类,最上层的接口是importSelctor,重要的一个实现方法是selectorImports方法:
 

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.filter(configurations, autoConfigurationMetadata);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return StringUtils.toStringArray(configurations);
        }
    }

可以对上述的代码进行猜测(大概知道每句代码的大体意思)。

AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);//就是获取自动装配的元数据(通过英文意思知道),具体是什么可以不做深究。

AnnotationAttributes attributes = this.getAttributes(annotationMetadata);// 获取标注@EnableAutoConfiguration的元数据。

List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);//获取候选的自动装配类集合

configurations = this.removeDuplicates(configurations); // 移除重复对象

Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);//需要排除的类的名单

configurations = this.filter(configurations, autoConfigurationMetadata); // 将排除后的对象进行过滤,注意:autoConfigurationMetadata 是第一步骤获取的自动装配的对象,因为过滤信息应该是保存在autoConfigurationMetadata 对象中的。

this.fireAutoConfigurationImportEvents(configurations, exclusions);// 触发了导入事件,导入的对象就是经过过滤后的对象集合。

问题:

上述的猜测不敢保证全对,但是基本知道方法的作用,可以得出以下结论:

1、getCandidateConfigurations方法可以知道怎么装配组件,装配哪些组件?

答:getCandidateConfigurations方法根据MATA-INF/spring.factories资源内容作为propertise文件读取,合并到一个key为接口的全类名,value为接口的实现类的列表的map。如下图所示:

2、getExclusions可以知道怎么排除exclude配置的类?

答:getExclusions是根据在注解@EnableAutoConfiguration中配置的exclude和excludeName以及再配置文件配置的spring.autoconfigure.exclude累加到排除集合exclude.

概括如下:

1、通过springfactoriesLoader#loadFactoryNames方法读取所有MATA/INFO/Spring.factorise资源中@EnableAutoConfiguration关联的自动装配class集合。

2、根据在注解@EnableAutoConfiguration中配置的exclude和excludeName以及再配置文件配置的spring.autoconfigure.exclude累加到排除集合exclude.

3、检查自动装配class排除集合是否合法。

4、排除候选自动装配集合排除名单。

5、过滤候选自动装配class集合下的class不存在的成员。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值