Spring Boot 最大的特点(亮点)就是自动配置 AutoConfiguration

下面,先说一下 @EnableAutoConfiguration ,然后再看源代码,到底自动配置是怎么配置的

1.  @EnableAutoConfiguration

@SpringBootApplication是一个复合注解,本节我们重点关注 @EnableAutoConfiguration

自动配置类是常规的Spring @Configuration bean。它们使用SpringFactoriesLoader机制定位。通常,自动配置bean是@Conditional Bean(最经常使用@ConditionalOnClass和@ConditionalOnMissingBean注解)

在@EnableAutoConfiguration注解上有一个@Import注解

@Import这个注解表明要导入的一个或多个组件类,通常是@Configuration类。

@Import注解提供与Spring XML中的<import />元素等效的功能。允许导入@Configuration类,ImportSelector和ImportBeanDefinitionRegistrar实现以及常规组件类。

根据导入的@Configuration类的AnnotationMetadata,返回AutoConfigurationImportSelector.AutoConfigurationEntry。

方法的参数AnnotationMetadata代表配置类上的注解元数据,方法的返回值是应该被导入的自动配置类

首先,获取配置类上的注解的属性

又是熟悉的方法:SpringFactoriesLoader.loadFactoryNames()

在所有 META-INF/spring.factories 文件中查找 org.springframework.boot.autoconfigure.EnableAutoConfiguration

然后,去重

然后,再排除一些,根据注解属性中明确指定的exclude

删除所有需要排除的

然后,过滤掉一些不需要的

根据对所有的需要自动配置的类应用那三个过滤器

最终剩下的就是真正需要导入的,或者说真正需要自动配置的

在众多需要自动配置的类中,我们挑一个熟悉的来看一下,就挑org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration

看这注解,当classpath中有RedisOperations时才会自动配置该类,当有RedisConnectionFactory且没有redisTemplate时才会创建一个redisTemplate,同理,有RedisConnectionFactory且没有stringRedisTemplate时才会创建一个stringRedisTemplate

回顾一下

1、在所有 META-INF/spring.factories 文件中查找 org.springframework.boot.autoconfigure.EnableAutoConfiguration,返回一个List<String>

2、对上一步返回的List去重

3、根据注解exclude属性排除List中的一些元素

4、根据AutoConfigurationImportFilter过滤掉一些不需要自动配置的元素

5、讲过以上四步,List中剩下的元素就是最终需要自动配置的元素(类)

至此,只是筛选出了哪些类需要自动配置,但还没有真正装配(实例化),真正实例化Bean是在Spring Boot启动时刷新ApplicationContext时做的

注解只是个标记,是给反射用的,有注解必然有处理它的类

接下来,分析源码,看看究竟什么时候开始真正自动装配

2.  Spring Boot 自动配置源码分析

又来到了熟悉的SpringApplication.run()方法这里,这一次,重点看其中的三步:createApplicationContext()、prepareContext() 和 refreshContext()

首先看createApplicationContext()

看看AnnotationConfigServletWebServerApplicationContext有多复杂

创建了两个BeanDefinition分别是AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner,它们都是用来查找并加载Bean定义的,只是方式不同而已

下面重点看一下AnnotatedBeanDefinitionReader

(PS:其实,这里注册了很多BeanPostProcessor,有处理Autowired的AutowiredAnnotationBeanPostProcessor,由于本节主要讲自动配置的,所以我们重点关注ConfigurationClassPostProcessor)

先做个笔记:

1、ApplicationContext 是 AnnotationConfigServletWebServerApplicationContext

2、构造了一个AnnotatedBeanDefinitionReader,大家要明白BeanDefinitionReader是用来加载Bean定义的

3、把这个AnnotatedBeanDefinitionReader注册(关联)到该ApplicationContext

4、在构造AnnotatedBeanDefinitionReader的时候注册了很多Processors

可见AnnotatedBeanDefinitionReader真的是相当相当重要,而重中之重是org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors()

我们单独把这段拿出来再看一下

如果没有这个BeanDefinition的时候就添加一个

CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME 对应的是 ConfigurationClassPostProcessor

先记住这一点,后面会用到

接下来,看prepareContext()

 

重点看SharedMetadataReaderFactoryContextInitializer

好,记住这一点,此处添加了一个BeanFactoryPostProcessor,它是一个CachingMetadataReaderFactoryPostProcessor

最后,再来看refreshContext()

调用是Spring的refresh()

重点看 invokeBeanFactoryPostProcessors 调用所有已注册的BeanPostProcessor

这里,调用getBeanFactoryPostProcessors()返回的BeanFactoryPostProcessors中有CachingMetadataReaderFactoryPostProcessor

好,记住这一点

继续看PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()

好,看CachingMetadataReaderFactoryPostProcessor#postProcessBeanDefinitionRegistry()

又看到了熟悉的AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME,我们知道它是ConfigurationClassPostProcessor

回到PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()继续往下看

得到ConfigurationClassPostProcessor

接下来,调用postProcessBeanDefinitionRegistry

方法太长,就不截全图了,总之就是找到配置类,开始解析配置类了,只看重点

到这里终于和我们前面讲的@EnableAutoConfiguration自动配置开始沾点儿边了

下面,重点来了,核心中的核心

终于写完了,累死我了

Spring Boot 自动配置 源码分析的更多相关文章

  1. Spring Boot自动配置源码解析(基于Spring Boot 2.0.2.RELEASE)

    在Spring Boot官方介绍中,首一段话是这样的(如下图).我们可以大概了解到其所表达的含义:我们可以利用Spring Boot写很少的配置来创建一个非常方便的基于Spring整合第三方类库的单体 ...

  2. spring boot 2.0 源码分析(一)

    在学习spring boot 2.0源码之前,我们先利用spring initializr快速地创建一个基本的简单的示例: 1.先从创建示例中的main函数开始读起: package com.exam ...

  3. spring boot 2.0 源码分析(四)

    在上一章的源码分析里,我们知道了spring boot 2.0中的环境是如何区分普通环境和web环境的,以及如何准备运行时环境和应用上下文的,今天我们继续分析一下run函数接下来又做了那些事情.先把r ...

  4. spring boot 2.0 源码分析(二)

    在上一章学习了spring boot 2.0启动的大概流程以后,今天我们来深挖一下SpringApplication实例变量的run函数. 先把这段run函数的代码贴出来: /** * Run the ...

  5. spring boot 2.0 源码分析(三)

    通过上一章的源码分析,我们知道了spring boot里面的listeners到底是什么(META-INF/spring.factories定义的资源的实例),以及它是创建和启动的,今天我们继续深入分 ...

  6. spring boot 2.0 源码分析(五)

    在上一篇文章中我们详细分析了spring boot是如何准备上下文环境的,今天我们来看一下run函数剩余的内容.还是先把run函数贴出来: /** * Run the Spring applicati ...

  7. Springboot 系列(三)Spring Boot 自动配置原理

    注意:本 Spring Boot 系列文章基于 Spring Boot 版本 v2.1.1.RELEASE 进行学习分析,版本不同可能会有细微差别. 前言 关于配置文件可以配置的内容,在 Spring ...

  8. SpringBoot自动配置源码调试

    之前对SpringBoot的自动配置原理进行了较为详细的介绍(https://www.cnblogs.com/stm32stm32/p/10560933.html),接下来就对自动配置进行源码调试,探 ...

  9. Spring Boot自动配置与Spring 条件化配置

    SpringBoot自动配置 SpringBoot的自动配置是一个运行时(应用程序启动时)的过程,简化开发时间,无需浪费时间讨论具体的Spring配置,只需考虑如何利用SpringBoot的自动配置即 ...

随机推荐

  1. 图解算法——KMP算法

    KMP算法 解决的是包,含问题. Str1中是否包含str2,如果包含,则返回子串开始位置.否则返回-1. 示例1: Str1:abcd123def Str2:123d 暴力法: 从str1的第一个字 ...

  2. uni-app 支持第三方 H5 离线包

    uni-app 支持第三方 H5 离线包 https://uniapp.dcloud.io/ https://github.com/dcloudio/uni-app refs xgqfrms 2012 ...

  3. js & input event & input change event

    js & input event & input change event vue & search & input change <input @click=& ...

  4. 专利 & 发明专利 & 专利查询

    专利 & 发明专利 & 专利查询 PDF 文档中表格解析的方法.系统.存储介质及电子设备 中国专利公布公告 http://epub.sipo.gov.cn/index.action 中 ...

  5. JsBridge & Android WebView

    JsBridge & Android WebView webview loadUrl addJavascriptInterface .setJavaScriptEnabled(true); f ...

  6. 比特币跌破3.5万美元,巨鲸们将目光瞄向SPC算力币

    比特币最近又迎来了大幅下跌,截至周三(1月20日),比特币跌幅超过5%,跌破3.5万美元.很显然,比特币没有预期那样顺顺利利地登顶4万美元,反而又出现了回调迹象.有些巨鲸们在大肆囤币,然而也有些巨鲸们 ...

  7. NGK是如何运用IPFS分布式存储的?

    整个夏季,除了天气的火热,还有的火热莫过于IPFS挖矿这个领域了.IPFS的概念火热到,你可以看到到处都在卖IPFS矿机.那么,是什么原因导致IPFS这么火呢?在这之前,我们先了解一下什么是IPFS技 ...

  8. hadoop环境搭建:完全分布式

    目录 1.硬件配置 2.软件版本 3.准备工作 3.1.建立虚拟机,网络设置为桥接模式 3.2.更改主机名 3.3.绑定主机名和IP,建立各主机间的联系 3.4.关闭防火墙 3.5.配置宿主机host ...

  9. 为什么我们在定义HashMap的时候,就指定它的初始化大小呢

    在当我们对HashMap初始化时没有设置初始化容量,系统会默认创建一个容量为16的大小的集合.当HashMap的容量值超过了临界值(默认16*0.75=12)时,HashMap将会重新扩容到下一个2的 ...

  10. gojs插件使用教程

    目录 一.简介 二.简单使用 三.重要概念 1.TextBlock创建文本 2.Shape图形 3.Node节点(文本与图形结合) 4.Link箭头 四.数据绑定(前后端交互数据渲染) 五.去除水印 ...