深度剖析Spring Boot自动装配机制实现原理,原理解析

@Import(AutoConfigurationImportSelector.class)

public @interface EnableAutoConfiguration {

但是从EnableAutoCOnfiguration上面的import注解来看,这里面并不是引入另外一个Configuration。而是一个ImportSelector。这个是什么东西呢?

AutoConfigurationImportSelector是什么?


Enable注解不仅仅可以像前面演示的案例一样很简单的实现多个Configuration的整合,还可以实现一些复杂的场景,比如可以根据上下文来激活不同类型的bean,@Import注解可以配置三种不同的class

  1. 第一种就是前面演示过的,基于普通bean或者带有@Configuration的bean进行诸如

  2. 实现ImportSelector接口进行动态注入

实现ImportBeanDefinitionRegistrar接口进行动态注入

CacheService


public class CacheService {

}

LoggerService


public class LoggerService {

}

EnableDefineService


@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited --允许被继承

@Import({GpDefineImportSelector.class})

public @interface EnableDefineService {

String\[\] packages() default "";

}

GpDefineImportSelector


public class GpDefineImportSelector implements ImportSelector {

@Override
public String\[\] selectImports(AnnotationMetadata annotationMetadata) {
    //获得指定注解的详细信息。我们可以根据注解中配置的属性来返回不同的class,
    //从而可以达到动态开启不同功能的目的

annotationMetadata.getAllAnnotationAttributes(EnableDefineService.class.getName(),true)

        .forEach((k,v) -> {
            log.info(annotationMetadata.getClassName());
            log.info("k:{},v:{}",k,String.valueOf(v));
        });
    return new String\[\]{CacheService.class.getName()};
}

}

EnableDemoTest


@SpringBootApplication

@EnableDefineService(name = “gupao”,value = “gupao”)

public class EnableDemoTest {

public static void main(String\[\] args) {
    ConfigurableApplicationContext ca=SpringApplication.run(EnableDemoTest.class,args);
    System.out.println(ca.getBean(CacheService.class));
    System.out.println(ca.getBean(LoggerService.class));
}

}

了解了selector的基本原理之后,后续再去分析AutoConfigurationImportSelector的原理就很简单了,它本质上也是对于bean的动态加载。

@EnableAutoConfiguration注解的实现原理


了解了ImportSelector和ImportBeanDefinitionRegistrar后,对于EnableAutoConfiguration的理解就容易一些了

它会通过import导入第三方提供的bean的配置类:AutoConfigurationImportSelector

@Import(AutoConfigurationImportSelector.class)

从名字来看,可以猜到它是基于ImportSelector来实现基于动态bean的加载功能。之前我们讲过Springboot @Enable*注解的工作原理ImportSelector接口selectImports返回的数组(类的全类名)都会被纳入到spring容器中。

那么可以猜想到这里的实现原理也一定是一样的,定位到AutoConfigurationImportSelector这个类中的selectImports方法

selectImports


public String[] selectImports(AnnotationMetadata annotationMetadata) {

if (!isEnabled(annotationMetadata)) {

  return NO\_IMPORTS;

}

// 从配置文件(spring-autoconfigure-metadata.properties)中加载 AutoConfigurationMetadata

AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader

     .loadMetadata(this.beanClassLoader);

// 获取所有候选配置类EnableAutoConfiguration

AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(

     autoConfigurationMetadata, annotationMetadata);

return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());

}

getAutoConfigurationEntry


protected AutoConfigurationEntry getAutoConfigurationEntry(

  AutoConfigurationMetadata autoConfigurationMetadata,
  AnnotationMetadata annotationMetadata) {

if (!isEnabled(annotationMetadata)) {

  return EMPTY\_ENTRY;

}

//获取元注解中的属性

AnnotationAttributes attributes = getAttributes(annotationMetadata);

//使用SpringFactoriesLoader 加载classpath路径下META-INF\spring.factories中,

//key= org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的value

List configurations = getCandidateConfigurations(annotationMetadata,

     attributes);

//去重

configurations = removeDuplicates(configurations);

//应用exclusion属性

Set exclusions = getExclusions(annotationMetadata, attributes);

checkExcludedClasses(configurations, exclusions);

configurations.removeAll(exclusions);

//过滤,检查候选配置类上的注解@ConditionalOnClass,如果要求的类不存在,则这个候选类会被过滤不被加载

configurations = filter(configurations, autoConfigurationMetadata);

//广播事件

fireAutoConfigurationImportEvents(configurations, exclusions);

return new AutoConfigurationEntry(configurations, exclusions);

}

本质上来说,其实EnableAutoConfiguration会帮助springboot应用把所有符合@Configuration配置都加载到当前SpringBoot创建的IoC容器,而这里面借助了Spring框架提供的一个工具类SpringFactoriesLoader的支持。以及用到了Spring提供的条件注解@Conditional,选择性的针对需要加载的bean进行条件过滤

SpringFactoriesLoader


为了给大家补一下基础,我在这里简单分析一下SpringFactoriesLoader这个工具类的使用。它其实和java中的SPI机制的原理是一样的,不过它比SPI更好的点在于不会一次性加载所有的类,而是根据key进行加载。

首先,SpringFactoriesLoader的作用是从classpath/META-INF/spring.factories文件中,根据key来加载对应的类到spring IoC容器中。接下来带大家实践一下

创建外部项目jar


org.springframework

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
[外链图片转存中…(img-s3gv6pou-1711178748727)]
[外链图片转存中…(img-3k9ltEhm-1711178748727)]
[外链图片转存中…(img-wq1vYyrg-1711178748728)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-kv6NX4nQ-1711178748728)]

  • 15
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值