博文目录
文章目录
- 内容总结
- refresh - invokeBeanFactoryPostProcessor
- ConfigurationClassPostProcessor - postProcessBeanDefinitionRegistry
- ConfigurationClassParser - parse
- 部分工具用法说明
- 大致流程
内容总结
refresh - invokeBeanFactoryPostProcessor
Spring 启动过程中, 在 refresh 的 invokeBeanFactoryPostProcessor 阶段, Spring 会获取到系统中所有的 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor 组件, 两者的关系与功能如下
- BeanFactoryPostProcessor
- postProcessBeanFactory, 可以从 BeanFactory 中获取并修改 BeanDefinition
- BeanDefinitionRegistryPostProcessor, 是 BeanFactoryPostProcessor 的子接口, 拥有其父接口的能力
postProcessBeanFactory
, 可以从 BeanFactory 中获取并修改 BeanDefinitionpostProcessBeanDefinitionRegistry
, 可以向 BeanFactory 中注册 BeanDefinition
Spring 在 invokeBeanFactoryPostProcessor 阶段, 会将这两种组件分组并排序, 先执行所有 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法, 再执行所有 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法
在这些组件中, 有一个 ConfigurationClassPostProcessor
, 负责配置类的扫描与解析工作, 它实现了 BeanDefinitionRegistryPostProcessor 接口, 即同时实现了 postProcessBeanDefinitionRegistry 与 postProcessBeanFactory 两个方法, postProcessBeanDefinitionRegistry 方法内就会做配置类的解析, 扫描, 注册 BeanDefinition 等工作
ConfigurationClassPostProcessor - postProcessBeanDefinitionRegistry
大致流程
- 首先获取到所有 BeanDefinition 的 Names, 大致有如下内容
- new AnnotationConfigApplicationContext 时传入的配置类, 在内部被注册
- new AnnotatedBeanDefinitionReader 时注册的一些基础架构组件
- 因为还没有开始扫描并注册自定义 BeanDefinition, 所以这里不会包含这些
- 遍历并获取对应的 BeanDefinition, 根据缓存判断是否是已经解析过的配置类
- 如果该 BeanDefinition 有 configurationClass 属性, 则说明该 BeanDefinition 是一个配置类, 且已经被解析过了, 不需要再次解析
- 如果没有解析过, 则判断该 BeanDefinition 是否符合配置类的定义, 符合配置类定义的会被添加到候选项列表中
什么是配置类?
有 @Configuration 注解, 且注解的 proxyBeanMethods 属性的值为 true, 则该类是配置类, 且是 FULL 类型的
有 @Configuration 注解, 但注解的 proxyBeanMethods 属性的值为 false, 则该类是配置类, 但是是 LITE 类型的
没有 @Configuration 注解, 且类不是接口, 且满足下面两个条件中的任意一个, 同样是配置类, 是 LITE 类型的
类上有 @Component, @ComponentScan, @Import, @ImportResource 中的任意一个
类里有 @Bean 注解标注的方法
- 如果候选列表是空的, 说明没有找到配置类, 该方法终止
- 如果有找到候选项, 排序, 实例化 BeanNameGenerator 和 Environment
- 实例化一个配置类解析器
ConfigurationClassParser
- 使用配置类解析器来解析配置类, 如果解析的过程中发现了新的其他配置类, 则递归解析之
ConfigurationClassParser - parse
配置类解析器, 用来解析配置类
部分工具用法说明
@Component
, 如果一个类上有该注解及其其衍生注解, 如 @Controller, @Service, @Repository 等, 则 Spring 扫描过程中, 该类会被扫描成为 BeanDefinition, 最终被创建为 Bean@ComponentScan
, Spring 会扫描通过该注解指定的包及其子包, 并查找带有@Component 注解及其其衍生注解, 如 @Controller, @Service, @Repository 等的类, 将其注册成为 BeanDefinition, 最终被创建为 Bean@ComponentScans
, 里面可以放多个 @ComponentScan, 每一个子项都将依次被扫描@Import
, 通过该注解将类引入 Spring, 和 @Bean 有部分功能重叠- 如果被引入的类是
ImportSelector
, 该接口定义了 selectImports 方法, 返回的是一组全限定类名数组, 这些类最终被注册成为 BeanDefinition, 而实现 ImportSelector 的类则不会被注册成为 BeanDefinition- 如果被引入的类是
DeferredImportSelector
, 延迟导入, ImportSelector 在解析配置类的时候就顺带处理掉了, 而 DeferredImportSelector 在解析配置类时只是将其加入到一个容器中, 等到所有的配置类都解析完成后才会处理
- 如果被引入的类是
- 如果被引入的类是
ImportBeanDefinitionRegistrar
, 该接口可以向 BeanFactory 注册 BeanDefinition, 定义了两个重载的 registerBeanDefinitions 方法, 一个需要指定 BeanName, 一个则使用名称生成器 如果被引入的类不属于上述情况
, 则该类被注册成为 BeanDefinition, BeanName 是全限定类名, 而通过 @Bean 注解的方法注册的 BeanDefinition, BeanName 是方法名
- 如果被引入的类是
@ImportResource
, 用于导入 XML 配置文件@PropertySource
, 用于让 Spring 加载特定的属性配置文件到 Environment, 通过 @Value 获取并使用之. 和 @ConfigurationProperties 组合使用, 可以将属性文件与一个类绑定, 将属性文件中的变量值注入到该类的成员变量中@PropertySources
, 里面可以放多个 @PropertySource