目录
SpringBoot自动配置
SpringBoot自动配置-AutoConfiguration
配置类-ConfigurationClass
-
广义的: 被注解@Component直接或间接修饰的某个类 即我们常说的Spring组件
被@Component修饰的类本身作为Bean
-
狭义的: 被注解@Configuration所修饰的某个类 又称@Configuration类
被@Configuration修饰的类本身和其中被@Bean修饰的方法的返回值作为Bean
SpringBoot自动配置的例子
如自动配置redis
-
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
-
配置redis服务器
spring:
redis:
database: 0
host: 127.0.0.1
port: 6379
password: 123456
-
直接使用RedisTemplate
@Autowired
private RedisTemplate redisTemplate;
整个过程中 我们没有通过任何操作在applicationContext中注册RedisTemplate 这个Bean
SpringBoot启动流程
从SpringApplication.run(…)开始:
-
创建一个ApplicationContext实例 即创建ioc容器
-
注册主类到ioc容器中(简单但重要的一步)
被@SpringBootApplication所修饰的类
一般为main方法所在的类
这个类将作为遍历配置类的起点
-
递归加载并处理所有的配置类
SpringBoot自动找到所有的配置类
然后加载和处理他们
-
实例化所有的单例Bean
实例化所有的单例Bean
依赖注入和自动装配就属于其中的环节
-
如果是web应用 启动一个web服务器
步骤3-加载并处理所有的配置类
-
SpringBoot首先处理朱磊的@ComponentScan注解
扫描指定的package 得到一系列的配置类
包括@Component修饰的 @Configuration修饰的类
如果在这些扫描得到的配置类上存在@ComponentScan 则递归处理
以此步骤加载所有的程序中定义的配置类
-
处理注解@Import
根据Import注解的处理结果 可以得到一系列被导入的配置类
如果此步骤中得到的配置类上依然存在@Import注解 也是通过递归处理的
-
处理被@Bean修饰的方法
-
处理@Import导入的ImportBeanDefinitionRegistrar
-
加入到一个全局的配置类集合中
通过递归遍历 SpringBoot发现了所有的配置类
对配置类进行解析处理 并将得到的BeanDefinition注册到ioc容器中
@ComponentScan注解
-
对指定的package进行扫描 找到其中符合条件的类
-
默认是搜索被注解@Component修饰的配置类 (包括直接修饰的和间接修饰的)
-
通过属性basePackages或basePackageClasses来指定要进行扫描的package
-
如果未指定package 则默认扫描当前@ComponentScan所修饰的类所在的package
@Import注解
import导入普通类例子
导入ImportSelector接口的实现类例子
可以通过@import导入一个ImportSelector实现类
ImportSelector接口中的selectImports方法
他的返回值是一个字符串数组
数组中的每一个元素都代表一个将被导入的配置类的全限定名
利用这一特性 我们可以给ioc容器动态的导入多个配置类
导入接口ImportBeanDefinitionRegistrar实现类例子
在ImportBeanDefinitionRegistrar的实现类中
可以手动向registry(可以理解为目标ioc容器)中注册多个Bean定义
从而实现个性化定制
小结-SpringBoot加载配置类的方式
-
使用注解@ComponentScan
-
使用注解@Import
实现自动配置的方式
如果@ComponentScan实现
通过包扫描向ioc容器中注册第三方jar包中定义的Bean
需要记住每个第三方jar包中需要被扫描的包的名称
然后在程序中进行扫描包
性能较差 使用不便 不符合SpringBoot开箱即用的理念
如果使用@Import导入普通类实现
需要记住具体的类名
虽然性能相比包扫描ComponentScan好
但依然使用不便
如果使用@Import导入注册器ImportBeanDefinitionRegistrar实现
ImportBeanDefinitionRegistrar导入的不是Bean
而是BeanDefinition
是针对@Bean方法的补充
用于实现自动配置并不恰当
(不理解…)
如果使用@Import导入选择器ImportSelector
SpringBoot实现自动配置使用的方式
@SpringBootApplicaton被@EnableAutoConfiguration注解修饰
@EnableAutoConfiguration注解被@Import(AutoConfigurationImportSelector.class)修饰
SpringBoot通过@Import(AutoConfigurationImportSelector.class)来实现自动配置
@SpringBootApplication注解结构
-
@SpringBootApplication修饰的类 会被@Configuration间接修饰 即"源配置类"
-
SpringBoot框架会对"源配置类"所在的package进行组件扫描(ComponentScan)
-
SpringBoot通过@Import(AutoConfigurationImportSelector.class)来实现自动配置
SpringBoot自动装配的原理
如何实现AutoConfigurationImportSelector
"开箱即用"即用户只需要引入jar包即可
不需要关心jar包中有哪些自动装配类
类名是什么 所在的包名是什么 都不需要用户关心
SpringBoot采用SpringFactories机制实现这一点
SpringFactories机制
核心逻辑为:
从classpath中读取到所有jar包中的配置文件META-IF/spring.factories
然后根据指定的key从配置文件中解析出对应的value
AutoConfigurationImportSelector
在AutoConfigurationImportSelector的selectImports方法中:
-
通过SpringFactories机制加载配置文件
通过ClassLoader去获取classpath中的配置文件META-INF/spring.factories
-
找出所有的自动配置类
在所有的配置文件META-INF/spring.factories中
筛选出以EnableAutoConfiguration.class为key的 符合条件的配置类
(spring.factories内容格式为:“key=value1,value2,…valueN”)
-
根据@Conditional过滤掉不必要的自动装配类
@Conditional 提供了配置过滤机制
在特定条件满足时才会向ioc容器注册指定组件
可以理解为一种特殊的if语句(待补充)
SpringFactories机制对比JavaSPI机制
-
相同的:
-
不同的
-
约定的配置文件路径不同
-
配置文件内容不同
-
SpringFactories机制:
内容格式为:“key=value1,value2,…valueN”
-
JavaSPI机制:
内容格式是serviceProvider的类全限定名
多个Provider类的话每个类名占据一行
-
loader类不同
示意图
总结
SpringBoot实现bean自动配置
需要获知 在第三方jar包中 那些类是需要被配置的bean
只要能够获知这一点 就可以与配置程序中自定义bean相同的方式来处理这些类
获知这一点是使用了一种类似JavaSPI机制的方式:SpringFactories机制
SpringBoot在启动时 读取classpath下的所有spring.factories文件
从key为EnableAutoConfiguration.class的value中获取到所有需要进行自动配置的类的全限定名
至此 springBoot获取了实现自动配置需要的所有信息
此文章为https://www.bilibili.com/video/BV1NY411P7VX/?spm_id_from=333.788&vd_source=e974e5b422b5e93d638b7ac74272a918视频的学习笔记
感谢原内容作者码场安员外