Spring Boot 自动配置 源码分析
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 自动配置 源码分析的更多相关文章
- Spring Boot自动配置源码解析(基于Spring Boot 2.0.2.RELEASE)
在Spring Boot官方介绍中,首一段话是这样的(如下图).我们可以大概了解到其所表达的含义:我们可以利用Spring Boot写很少的配置来创建一个非常方便的基于Spring整合第三方类库的单体 ...
- spring boot 2.0 源码分析(一)
在学习spring boot 2.0源码之前,我们先利用spring initializr快速地创建一个基本的简单的示例: 1.先从创建示例中的main函数开始读起: package com.exam ...
- spring boot 2.0 源码分析(四)
在上一章的源码分析里,我们知道了spring boot 2.0中的环境是如何区分普通环境和web环境的,以及如何准备运行时环境和应用上下文的,今天我们继续分析一下run函数接下来又做了那些事情.先把r ...
- spring boot 2.0 源码分析(二)
在上一章学习了spring boot 2.0启动的大概流程以后,今天我们来深挖一下SpringApplication实例变量的run函数. 先把这段run函数的代码贴出来: /** * Run the ...
- spring boot 2.0 源码分析(三)
通过上一章的源码分析,我们知道了spring boot里面的listeners到底是什么(META-INF/spring.factories定义的资源的实例),以及它是创建和启动的,今天我们继续深入分 ...
- spring boot 2.0 源码分析(五)
在上一篇文章中我们详细分析了spring boot是如何准备上下文环境的,今天我们来看一下run函数剩余的内容.还是先把run函数贴出来: /** * Run the Spring applicati ...
- Springboot 系列(三)Spring Boot 自动配置原理
注意:本 Spring Boot 系列文章基于 Spring Boot 版本 v2.1.1.RELEASE 进行学习分析,版本不同可能会有细微差别. 前言 关于配置文件可以配置的内容,在 Spring ...
- SpringBoot自动配置源码调试
之前对SpringBoot的自动配置原理进行了较为详细的介绍(https://www.cnblogs.com/stm32stm32/p/10560933.html),接下来就对自动配置进行源码调试,探 ...
- Spring Boot自动配置与Spring 条件化配置
SpringBoot自动配置 SpringBoot的自动配置是一个运行时(应用程序启动时)的过程,简化开发时间,无需浪费时间讨论具体的Spring配置,只需考虑如何利用SpringBoot的自动配置即 ...
随机推荐
- Leetcode(9)-回文数
判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数. 示例 1: 输入: 121 输出: true 示例 2: 输入: -121 输出: false 解释: 从左向 ...
- npm config set registry
npm config set registry $ npm config set registry $ npm config set registry https://registry.your-re ...
- 惠普机械键盘 K10GL 使用评测
惠普机械键盘 GK100 使用评测 手感太差,不是 RGB 背光 惠普(HP) K10GL 机械键盘 有线 LED背光机械键盘 87键 混光青轴 refs https://item.jd.com/10 ...
- npm fetch All In One
npm fetch All In One fetch for TypeScript { "compilerOptions": { "lib": ["D ...
- CSS selector All In One
CSS selector All In One CSS selector https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors ...
- GitHub 500 error
GitHub 500 error 无法访问了, GitHub 挂了又! error reports Downdetector Github down? Current service status a ...
- node.js 如何处理一个很大的文件
node.js 如何处理一个很大的文件 思路 arraybuffer 数据分段 时间分片 多线程 web workers sevice workers node.js 如何处理一个很大的文件 http ...
- taro css 转换 bug
taro css 转换 bug https://nervjs.github.io/taro/docs/size.html https://nervjs.github.io/taro/docs/comp ...
- qt 取进程列表,读写内存, 写字节集
导入库 pro win32:LIBS += -lpsapi win32:LIBS += -lkernel32 获取列表 #include "mainwindow.h" #inclu ...
- Flutter DraggableScrollableSheet 可滚动对象的容器
文档 Example import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp ex ...