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的自动配置即 ...
随机推荐
- MySQL5.6 与 MySQL5.7 的区别
目录 编译安装区别 初始化的区别 其他区别 编译安装区别 # 5.7在编译安装的时候多了一个 boost 库 [root@db02 mysql-5.7.20]# yum install -y gcc ...
- Kubernetes安装EFK教程(非存储持久化方式部署)
1.简介 这里所指的EFK是指:ElasticSearch,Fluentd,Kibana ElasticSearch Elasticsearch是一个基于Apache Lucene的开源搜索和数据分析 ...
- AF_INET与套接字SOCKET
一.SOCKET--套接字 套接字最初是为同一主机上的应用程序所创建,使得主机上运行的一个程序(又名一个进程)与另一个运行的程序进行通信.这就是所谓的进程间通信(Inter Process Commu ...
- MacOS微信逆向分析-Frida
MacOS微信逆向分析-Frida 0.前言 PC下的微信二次开发相信大家都会了,那么本篇文章将带领大家使用Frida框架对Mac下微信来进行二次开发! PS:还有一种静态注入的方式也不错,但是考虑到 ...
- js create Array ways All In One
js create Array ways All In One ES6 const arr = [...document.querySelectorAll(`[data-dom="^div& ...
- TypeScript Version 23 Design Patterns
TypeScript Version 23 Design Patterns TypeScript 设计模式 https://refactoring.guru/design-patterns/types ...
- DataBase All in One
DataBase All in One DB SQL: relational database management system NoSQL(Not only SQL / Non SQL): key ...
- queueMicrotask & EventLoop & macrotask & microtask
queueMicrotask https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/queueMicro ...
- website captcha
website captcha 验证码 hCaptcha hCaptcha通过询问对人类来说很容易且对机器来说很困难的简单问题,可以帮助您喜欢的Web服务阻止机器人,垃圾邮件和滥用行为. https: ...
- Java中Singleton的三种实现方式解析
一.什么是Singleton? <设计模式>的作者.Eclipse和 Junit 的开发者 Erich Gamma 在它的理论体系中将 Singleton 定义为仅仅被实例化一次的类.在当 ...