一文读懂SpringBoot自动装配原理

SpringBoot 版本 : 2.2.1.RELEASE
关键词:@EnableAutoConfiguration,/META-INF/spring.factories,
/META-INF/spring-autoconfigure-metadata.properties

注:本文主要讲解一些比较重要的关键步骤,不能面面俱到,若有疑问,随时保持沟通

  • 大家都知道,SpringBoot 六大特性:
  • 创建独立的Spring应用
  • 嵌入式Web容器(可以以可执行jar方式运行,不需要部署WAR文件)
  • 提供固化的 "starter",简化构建配置
  • 当条件满足时自动地装配Spring或第三方库
  • 提供运维特性(Production-Ready)特性,如指标信息(Metrics)、健康检查、外部化配置。
  • 不需要XML配置
  • 其中有一项为自动装配功能,自动装配功能总体来说由 @EnableXXX注解 + @Import , 再配合@Conditional注解可以实现条件自动装配,在SpringBoot中核心注解为@EnableAutoConfiguration

1. @EnableAutoConfiguration注解

  • 通常情况下,springBoot应用启动类不会直接标注此注解,而是通过@SpringBootApplication注解来实现:
    image.png
    发现 @SpringBootApplication中包含了 @SpringBootConfiguration(等同于@Configuration)、@EnableAutoConfiguration、@ComponentScan 注解。

总结:在启动类上加上 @EnableAutoConfiguration 注解 或者@SpringBootApplication即可实现自动装配,推荐使用 @SpringBootApplication这个组合注解。

2. @EnableAutoConfiguration注解实现自动装配原理

  • 依照 @EnableXXX的驱动设计,@EnableAutoConfiguration 必然也是按照 @Import 配合 ImportSelector或者 ImportBeandefinetionRegistrar 接口编程的套路,查看@EnableAutoConfiguration注解源码:
    image.png
    ,果不其然,再进一步验证:
    image.png
    ,不知读者是否还记得作者之前写过的 SpringBoot启动 源码深度解析(三)里面会有@Import注解的详细解析过程及 DeferredImportSelector 与 ImportSelector的回调逻辑。
  • 此时相信读者已经知道大致的脉络了,那么我们就重点分析一下 AutoConfigurationImportSelector 这个 ImportSelector实现。
  • 正常情况下,若类实现了 ImportSelector接口,则会回调其相对于的 selectImports方法,但是我们通类的关系图发现AutoConfigurationImportSelector 直接实现的是 DeferredImportSelector,而这个 ImportSelector 如下:
    image.png
    是在Spring 4.0之后新增的延迟ImportSelector,且处理逻辑跟普通的 ImportSelector不同的是当前接口新定义了 Group的概念。
    image.png
    追踪 process方法如下:
    image.png
    image.png
    重点在于此处的 grouping.getImports(),我们发现是 ConfigurationClassParser的内部静态类 DeferredImportSelectorGrouping:
    image.png
    此类中的两个处理方法正正是关键的步骤,而这两个方法正是 DeferredImportSelector 中的内部接口 Group的实现去执行的然后我们发现Group的方法默认实现是AutoConfigurationImportSelector的内部静态类AutoConfigurationGroup,如下:
    image.png
    ,👍👍看到这里,读者要是对这些类的名称记得不是很清晰的话,这一段的说明我建议跟着作者的思路,在本地源码找到对应的位置 "递归以上描述",肯定会恍然大悟,若是熟悉的话可以直接跳过👍👍,然后分析:
  1. getAutoConfigurationMetadata()
image.png
image.png
image.png
  • SprinBoot框架层帮忙做的自动装配元数据
  1. AutoConfigurationEntry entry = getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata)
image.png
  • AnnotationAttributes attributes = getAttributes(annotationMetadata) 获取@EnableAutoConfiguration标注类的元信息。
  • List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes):由于返回的结果是候选类的集合,跟踪调用链会发现:
    image.png
    image.png

    返回的是 key = org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的values值,这些values即是SpringBoot默认的自动装配类,所以有时候读者阅读源码时,发现某些类莫名其妙的被装载到Spring容器中了,一部分原因可能是这个地方搞的鬼。
  1. configurations = removeDuplicates(configurations)
  • 移除重复定义的配置类( 利用set集合的不可重复性 )
  1. Set<String> exclusions = getExclusions(annotationMetadata, attributes)
  • 获取排除类名单,排除类可通过 exclude = {A.class.B.class}属性来排除指定的配置类。
  1. configurations = filter(configurations, autoConfigurationMetadata)
  • 经过去重和排除过的配置类再执行过滤操作,过滤代码:
    image.png
  • ①中 调用的是 SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader),也是在spring.factories中获取 AutoConfigurationImportFilter类型的过滤器,此处默认有

    image.png

  • ②中 分别执行配置类的match方法,由于 OnBeanCondition、OnClassCondition、OnWebApplicationCondition 均继承自 FilteringSpringBootCondition,match方法如下:

    image.png
    image.png

  • 通过上面三个子类的方法实现 ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata),此处拿OnBeanCondition类来分析

    image.png
    自动装配类集合迭代调用 autoConfigurationMetadata.getSet(autoConfigurationClass, "ConditionalOnBean")方法获取 配置类.ConditionalOnBean的元信息,即在元数据配置文件中的 values。
    image.png

    以 RedisCacheConfiguration为例,其 "conditionOnBean" 如下:
    image.png
    ,获取返回的values值后,再调用 getOutcome()方法计算匹配结果,最终判断是由
    image.png
    ClassNameFilter.MISSING#matches决定的。

  • 解析到这里,自动装配的底层实现细节基本已经说完了,底层实现稍微有点晦涩难懂,但是只要掌握关键性的类及注解的作用之后,再去了解源码基本上就可以手到擒来了。

总结:自动装配的流程
  • 添加 @SpringBootApplication 注解或者 @EnableAutoConfiguration
  • 通过 SpringFactoriesLoader.loadFactoryNames(...) 获取自动装配类,执行一系列的去重、排除等操作,然后通过过滤,通过判断当前类加载器是否是加载元数据的类加载器来决定 @ConditiionOnXXX 注解的装配过程。
  • 自动装配是SpringBoot的元数据配置文件(spring-autoconfigure-metadata.properties)中的配置类的选择性加载的过程。
  1. ☛ 文章要是勘误或者知识点说的不正确,欢迎评论,毕竟这也是作者通过阅读源码获得的知识,难免会有疏忽!
  2. 要是感觉文章对你有所帮助,不妨点个关注,或者移驾看一下作者的其他文集,也都是干活多多哦,文章也在全力更新中。
  3. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343