Spring 主要源码分析
Bean的生命周期为:BeanFactory初始化 - Bean注册 - 实例化 - 属性注入 - 初始化 - 后处理
Bean的注册
- 扫描:Spring通过配置(XML配置或Java配置)或自动扫描(
@ComponentScan
)来发现应用中定义的Bean。对于自动扫描,Spring会在指定的包路径下查找标注了@Component
、@Service
、@Repository
、@Controller
等注解的类 - 解析:一旦Bean被发现,Spring将解析Bean的定义信息,包括Bean的作用域(如单例、原型)、生命周期回调(如
@PostConstruct
、@PreDestroy
注解方法)、依赖注入的需求(通过@Autowired
、@Resource
等注解标记)等 ——BeanDefinition
- 注册:Spring将Bean的定义信息注册到
BeanDefinitionRegistry
中。这是一个重要步骤,因为注册后的Bean定义将被用于后续的Bean实例化和依赖注入过程。此时,Bean还没有被实例化。
BeanDefinition
Spring在初始化过程中,先收集所有bean的元数据信息并注册,bean的元数据描述为接口BeanDefinition
,该接口定义了你能想到的一切有关bean的属性信息
BeanDefinition衍生出一系列实现类
- AbstractBeanDefinition: 如同其他Spring类,大部分BeanDefinition接口的逻辑都由该抽象类实现
- GenericBeanDefinition: 是一站式、用户可见的bean definition;可见的bean definition意味着可以在该bean definition上定义post-processor来对bean进行操作
- RootBeanDefinition: 当bean definition存在父子关系的时候,RootBeanDefinition用来承载父元数据的角色(也可独立存在),同时它也作为一个可合并的bean definition使用,在Spring初始化阶段,所有的bean definition均会被(向父级)合并为RootBeanDefinition,子bean definition(GenericBeanDefinition/ChildBeanDefinition)中的定义会覆盖其父bean definition(由parentName指定)的定义
- AnnotatedBeanDefinition: 用来定义注解Bean Definition
BeanDefinitionHolder只是简单捆绑了BeanDefinition、bean-name、bean-alias,用于注册BeanDefinition及别名alias ^BeanDefinitionHolder
BeanRegistry
Bean的注册逻辑分为两步,一为BeanDefinition的注册,二为别名的注册
- BeanDefinition注册的定义在BeanDefinitionRegistry#registerBeanDefinition,其实现使用一个Map<String, BeanDefinition> 来保存bean-name和BeanDefinition的关系
- 别名的注册定义在AliasRegistry#registerAlias,其实现同样使用一个Map<String, String> 来保存别名alias-name和bean-name(或另一个别名alias-name)的关系
注意Bean的注册时机,通常应该在应用上下文的刷新过程之前进行(onRefresh()
)。一旦上下文被刷新,对Bean定义的任何修改可能不会被识别,或者可能会导致不一致的状态
Bean的实例化
BeanFactory
几个核心接口:
- AliasRegistry bean别名注册和管理
- BeanDefinitionRegistry bean元数据注册和管理
- SingletonBeanRegistry 单例bean注册和管理
- BeanFactory bean工厂,提供各种bean的获取及判断方法
通过上述的类依赖图,对于Bean的实例化,核心实现是在DefaultListableBeanFactory
DefaultListableBeanFactory - AbstractBeanFactory
bean的实例化过程发生在getBean调用阶段(对于singleton则发生在首次调用阶段),getBean的实现方法众多,我们追根溯源,找到最通用的方法AbstractBeanFactory#doGetBean
doGetBean
|
|
Bean Name的转换
在使用bean-name获取bean的时候,除了可以使用原始bean-name之外,还可以使用alias别名等,bean-name的转换则是将传入的’bean-name’一层层转为最原始的bean-name
- 函数canonicalName的作用则是利用别名注册aliasMap,将别名alias转为原始bean-name
- 函数transformedBeanName比较特殊,其是将FactoryBean的bean-name前缀 ‘&’ 去除
尝试获取单例
拿到原始的bean-name之后,便可以实例化bean或者直接获取已经实例化的singleton-bean
在获取singleton-bean的时候一般存在三种情况:1. 还未实例化(或者不是单例);2. 已经实例化;3. 正在实例化;
- 对于 “1. 还未实例化” ,返回null即可,后续进行实例化动作
- 对于 “2. 已经实例化”,直接返回实例化的singleton-bean
- 对于 “3. 正在实例化”,会存在循环依赖问题
Spring中对于singleton-bean,有一个sharedInstance的概念,在调用getSingleton
函数时,返回的不一定是完全实例化的singleton-bean,有可能是一个中间状态(创建完成,但未进行属性依赖注入及其他后处理逻辑),这种中间状态会通过getSingleton函数提前曝光出来,目的是为了解决循环依赖
因此,Spring通过提供三层缓存来解决循环依赖问题,并且可以通过这种机制实现诸多的PostProcessor增强Bean,例如AOP
- singletonObjects 缓存已经实例化完成的singleton-bean
-
earlySingletonObjects 缓存正在实例化的、提前曝光的singleton-bean,用于处理循环依赖
-
singletonFactories 缓存用于生成earlySingletonObject的 ObjectFactory
ObjectFactory,定义了一个用于创建、生成对象实例的工厂方法
|
|
因此getSingleton的逻辑如下:
NOTE: 在提前暴露实体中,将相应的ObjectFactory放入了singletonFactories
FactoryBean的处理(sharedInstance存在的逻辑)
==sharedInstance不一定是我们所需要的bean实例==
例如,我们在定义Bean的时候可以通过实现FactoryBean接口来定制bean实例化的逻辑(实现FactoryBean),通过注册FactoryBean类型的Bean,实例化后的原始实例类型同样为FactoryBean,但我们需要的是通过FactoryBean#getObject方法得到的实例,这需要针对FactoryBean做一些处理,即AbstractBeanFactory#getObjectForBeanInstance
Get the object for the given bean instance, either the bean instance itself or its created object in case of a FactoryBean. Now we have the bean instance, which may be a normal bean or a FactoryBean. If it’s a FactoryBean, we use it to create a bean instance.
该函数要实现的逻辑比较简单,如果sharedInstance是 FactoryBean,则使用getObject方法创建真正的实例
getObjectForBeanInstance是一个通用函数,并不只针对通过getSingleton得到的sharedInstance,任何通过缓存或者创建得到的 rawInstance,都需要经过getObjectForBeanInstance处理,拿到真正需要的 beanInstance
|
|
getObjectBeanInstance
在这个判断逻辑中,如果入参name以’&‘开头则直接返回,这里兼容了一种情况,如果需要获取/注入FactoryBean而不是getObject生成的实例,则需要在bean-name/alias-name前加入'&'
对于singleton,FactoryBean#getObject的结果会被缓存到factoryBeanObjectCache,对于缓存中不存在或者不是singleton的情况,会通过FactoryBean#getObject生成 ^factorybeangetobject
FactoryBeanRegistrySupport#getObjectFromFactoryBean
|
|
对于Singleton:
- 首先从缓存中尝试获取,如获取失败,调用[doGetObjectFromFactoryBean](#
FactoryBeanRegistrySupport doGetObjectFromFactoryBean
“wikilink”),其中内核是调用FactoryBean#getObject()方法 - 对于需要后处理的Bean,首先判断是否处于正在创建状态(
isSingletonCurrentlyInCreation
),并且通过this.beforeSingletonCreate()
this.afterSingletonCreation()
将实际的BeanPostProcessor
过程保护 - 对于
BeanPostProcessor
,调用this.postProcessObjectFromFactoryBean
,其具体实现在[AbstractAutowireCapableBeanFactory#applyBeanPostProcessorAfterInitialization](#AbstractAutowireCapableBeanFactory applyBeanPostProcessorAfterInitialization
“wikilink”)
FactoryBeanRegistrySupport#doGetObjectFromFactoryBean
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorAfterInitialization
postProcessAfterInitialization函数可以对现有bean instance做进一步的处理,甚至可以返回新的bean instance,这就为bean的增强提供了一个非常方便的扩展方式
加载Bean实例 (sharedInstance不存在的逻辑)
Bean的加载/创建分为三大部分
- 将BeanDefinition合并为RootBeanDefinition,类似类继承,子BeanDefinition属性会覆盖父BeanDefinition
- 依次加载所依赖的bean,对于有依赖的情况,优先递归加载依赖的bean
- 按照不同的bean类型,根据BeanDefinition的定义进行加载/创建
BeanDefinition合并 (RootBeanDefinition)
在AbstractBeanFactory#getMergedLocalBeanDefinition
中执行核心逻辑
加载dependes-On beans
|
|
该过程中涉及两个中间态
- dependentBeanMap 存储哪些bean依赖了我(哪些bean里注入了我) 如果 beanB -> beanA, beanC -> beanA,key为beanA,value为[beanB, beanC]
- dependenciesForBeanMap 存储我依赖了哪些bean(我注入了哪些bean) 如果 beanA -> beanB, beanA -> beanC,key为beanA,value为[beanB, beanC]
加载singleton bean实例
|
|
其中核心为createBean与getObjectForBeanInstance
- createBean 根据BeanDefinition的内容,创建/初始化 bean instance
- #getObjectBeanInstance 主要处理FactoryBean
createBean被包装在lambda(singletonFactory),重写ObjectFactory#getObject()
,作为[getSingleton](#DefaultSingletonBeanRegistry getSingleton(String, ObjectFactory)
“wikilink”)的参数
DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory)
同样的,会先在缓存中查找该singleton,如果不存在,创建的核心逻辑在于[createBean](#AbstractAutowireCapableBeanFactory createBean “wikilink”)
AbstractAutowireCapableBeanFactory#createBean
- resolveBeanClass 这一步骤用于锁定bean class,在没有显示指定beanClass的情况下,使用className加载beanClass
- 验证method overrides ==在BeanDefinitionReader 中有提到过lookup-method及replace-method,该步骤是为了确认以上两种配置中的method是否存在==
- 执行InstantiationAwareBeanPostProcessor前处理器(postProcessBeforeInstantiation)
如果这个步骤中生成了"代理"bean instance,则会有一个短路操作,
直接返回
该bean instance而不再执行doCreate,其中的核心逻辑为调用this.applyBeanPostProcessorsBeforeInstantiation()
^fcb215
|
|
- doCreateBean (AbstractAutowireCapableBeanFactory) 真正bean的创建及初始化过程在此处实现
doCreateBean
|
|
可以将该流程细分为如下:
- [创建Bean实体](#创建Bean实体
AbstractAutowireCapableBeanFactory createBeanInstance
“wikilink”) - [BeanDefinition后处理](#BeanDefinition后处理 -
AbstractAutowireCapableBeanFactory applyMergedBeanDefinitionPostProcessors
“wikilink”) - 提前暴露实体
- [属性注入](#属性注入 -
AbstractAutowireCapableBeanFactory populateBean
“wikilink”) - [初始化](#初始化 -
AbstractAutowireCapableBeanFactory initializeBean
“wikilink”) - [注册Disposable](#注册Disposable -
AbstractBeanFactory registerDisposableBeanIfNecessary
“wikilink”)
创建Bean实体 - AbstractAutowireCapableBeanFactory#createBeanInstance
- instanceSupplier 从上面的流程图可以看出,创建bean实体不一定会使用到构造函数,可以使用Supplier的方式
- factory method
工厂模式
@Configuration + @Bean的实现方式就是factory-bean + factory-method
[对应的参数获取](#
ConstructorResolver resolvePreparedArguments
“wikilink”) - 有参构造函数
AbstractAutowireCapableBeanFactory#autowireConstructor -> [ConstructorResolver#autowireConstructor](#
**ConstructorResolver autowireConstructor**
“wikilink”) - 无参构造函数 与有参构造创建过程一致,除了不需要参数的依赖注入,使用默认无参构造函数进行实例化
ConstructorResolver#resolvePreparedArguments
使用指定(类)bean的(静态)方法创建bean实体的逻辑在ConstructorResolver#instantiate(String, RootBeanDefinition, Object, Method, args),而真正的逻辑在SimpleInstantiationStrategy#instantiate(RootBeanDefinition, String, BeanFactory, Object, Method, Object…),其核心的执行逻辑非常简单,有了方法factoryMethod(factoryBean)及入参args,便可以调用该方法创建bean实体
|
|
factoryBean可以通过beanFactory.getBean获取到(正是当前在讲的逻辑),factoryMethod可以通过反射获取到,而入参args就从ConstructorResolver#resolvePreparedArguments
中获取,即是Spring中依赖注入的核心实现
该函数的作用是将BeanDefinition中定义的入参转换为需要的参数(==将BeanDefinitionReader中封装的对象转换==)
ConstructorResolver#autowireConstructor
同样的,调用ConstructorResolver#resolvePreparedArguments进行参数的解析和转换(参数的依赖注入),然后调用 [ConstructorResolver#instantiate](#ConstructorResolver instantiate
“wikilink”) 来创建Bean实例
ConstructorResolver#instantiate
内部并没有统一利用反射技术直接使用构造函数创建,而是通过InstantiationStrategy.instantiate
进行创建
- 没有设置override-method时,直接使用构造函数创建
- 设置了override-method时,使用cglib技术构造代理类,并代理override方法
Spring默认的实例化策略为CglibSubclassingInstantiationStrategy
BeanDefinition后处理 - AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors
在属性注入之前提供一次机会来对BeanDefinition进行处理,内部执行所有注册MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法
[!hint] MergedBeanDefinitionPostProcessor
MergedBeanDefinitionPostProcessor
是一个特定类型的BeanPostProcessor
。MergedBeanDefinitionPostProcessor
的postProcessMergedBeanDefinition
方法允许在实例化bean之后但在设置bean属性之前,对bean的定义(BeanDefinition
)进行后处理。这个阶段是用于修改或增强bean定义的,例如,可以解析注解并相应地修改BeanDefinition
的属性。
对于MergedBeanDefinitionPostProcessor
的实现类AutowiredAnnotationBeanPostProcessor
,其内部方法AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata 实现了两个注解类的解析 @Value 及 @Autowired ,找到注解修饰的Filed或者Method并缓存,具体逻辑在[属性注入](#属性注入 - AbstractAutowireCapableBeanFactory populateBean
“wikilink”) ^autowiredAnnotationBeanPostProcessor1
提前暴露实体
通过将AbstractAutowireCapableBeanFactory#getEarlyBeanReference封装为ObjectFactory,调用DefaultSingletonBeanRegistry#addSingletonFactory,将该ObjectFactory缓存在DefaultSingletonBeanRegistry.singletonFactories中,在getBean
逻辑中的getSingleton
会执行ObjectFactory将singleton提前暴露
==此处即为何时添加ObjectFactory进入singletonFactories中,解决循环依赖==
此时暴露的singleton-bean仅完成了bean的实例化,属性注入、初始化等逻辑均暂未执行
属性注入 - AbstractAutowireCapableBeanFactory#populateBean
在[创建Bean实体](#创建Bean实体 - AbstractAutowireCapableBeanFactory createBeanInstance
“wikilink”)中介绍了factory method方式及有参构造函数方式的参数注入逻辑,除此之外还有一种注入便是属性注入
流程中出现了两次InstantiationAwareBeanPostProcessor,在第一次出现中调用的postProcessorAfterInstantiation
也与前面的InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation相同,拥有短路操作:如果该步骤生成了"代理"bean instance,直接返回
该bean instance而不再执行后续的doCreate;如果有任意一个InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法返回false,则会跳出属性注入的逻辑,官方对此的解释如下
Give any InstantiationAwareBeanPostProcessors the opportunity to modify the state of the bean before properties are set. This can be used, for example, to support styles of field injection.
autowireByName及autowireByType方法作为"候补"补充BeanDefinition的propertyValues
PropertyValue中记录了需要注入的属性信息及需要注入的属性值,那BeanDefinition的propertyValues都来自哪里?xml中的bean配置、自定义的BeanDefinition等
通过注解修饰的属性(方法)通过InstantiationAwareBeanPostProcessor#postProcessProperties进行注入 -> ==AutowiredAnnotationBeanPostProcessor#postProcessProperties & CommonAnnotationBeanPostProcessor#postProcessProperties==
最后,通过AbstractAutowireCapableBeanFactory#applyPropertyValues 将PropertyValue中记录的需要注入的属性,已经依赖的类型(String、RuntimeBeanReference、等),根据不同的类型解析依赖的bean并设置到对应的属性上(==此过程与DefaultListableBeanFactory#doResolveDependency相似==)
初始化 - AbstractAutowireCapableBeanFactory#initializeBean
以上,完成了bean实例的创建和属性注入,之后还有一些初始化的方法,比如各种Aware的setXxx是如何调用的、@PostConstruct是怎么调用的?
注册Disposable - AbstractBeanFactory#registerDisposableBeanIfNecessary
至此,终于完成了bean实例的创建、属性注入以及之后的初始化,此后便可以开始使用了
在使用Spring的过程中经常还会碰到设置销毁逻辑的情况,如数据库连接池、线程池等等,在Spring销毁bean的时候还需要做一些处理,类似于C++中的析构
在bean的创建逻辑中,最后一个步骤则是注册bean的销毁逻辑(DisposableBean)
销毁逻辑的注册有几个条件
- 非prototype(singleton或者注册的scope)
- 非NullBean
- 指定了destroy-method(如xml中指定或者BeanDefinition中直接设置)或者存在**@PreDestroy** 注解的方法(CommonAnnotationBeanPostProcessor.requiresDestruction)
|
|
满足以上条件的bean会被封装为DisposableBeanAdapter,并注册在DefaultSingletonBeanRegistry.disposableBeans中
加载prototype bean实例
|
|
prototype bean的创建与singleton bean类似,只是不会缓存创建完成的bean
加载其他scope bean实例
scope,即作用域,或者可以理解为生命周期
上文介绍了singleton-bean及prototype-bean的创建过程,严格意义上讲以上两种都是一种特殊的scope-bean,分别对应ConfigurableBeanFactory#SCOPE_SINGLETON及ConfigurableBeanFactory#SCOPE_PROTOTYPE,前者作用域为整个IOC容器,也可理解为单例,后者作用域为所注入的bean,每次注入(每次触发getBean)都会重新生成
Spring中还提供很多其他的scope,如WebApplicationContext#SCOPE_REQUEST或WebApplicationContext#SCOPE_SESSION,前者作用域为一次web request,后者作用域为一个web session周期
自定义scope的bean实例创建过程与singleton bean的创建过程十分相似,需要实现Scope的get方法(org.springframework.beans.factory.config.Scope#get)
|
|
Scope接口除了get方法之外,还有一个remove方法,前者用于定义bean的初始化逻辑,后者用于定义bean的销毁逻辑
|
|
WebApplicationContext#SCOPE_SESSION对应的Scope实现见org.springframework.web.context.request.SessionScope
WebApplicationContext#SCOPE_REQUEST对应的Scope实现见org.springframework.web.context.request.RequestScope
以上两种Scope实现都较为简单,前者将初始化的bean存储在request attribute中,后者将初始化的bean存储在http session中
尝试类型转换
以上,完成了bean的创建、属性的注入、dispose逻辑的注册,但获得的bean类型与实际需要的类型可能依然不相符,在最终交付bean之前(getBean)还需要进行一次类型转换,使用PropertyEditor进行类型转换,将bean转换为真正需要的类型后,便完成了整个getBean的使命
Bean销毁过程
bean的创建过程始于DefaultListableBeanFactory#getBean,销毁过程则终于ConfigurableApplicationContext#close,跟踪下去,具体的逻辑在DefaultSingletonBeanRegistry#destroySingletons
- DefaultSingletonBeanRegistry.disposableBeans 需要注册销毁逻辑的bean会被封装为DisposableBeanAdapter并缓存在此处
- DefaultSingletonBeanRegistry.dependentBeanMap 对于存在依赖注入关系的bean,会将bean的依赖关系缓存在此处(dependentBeanMap: 哪些bean依赖了我; dependenciesForBeanMap: 我依赖了哪些bean)
从上图中可以看出,bean的销毁顺序与创建顺序正好相反,如果有 beanA –dependsOn–> beanB –> beanC ,创建(getBean)时一定是beanC -> beanB -> beanA,销毁时一定是 beanA -> beanB -> beanC,以此避免因为依赖关系造成的一些异常情况
循环依赖
earlySingletonObject是用来解决循环依赖的问题,具体时机是在实例化完后属性注入之前,会提前将当前的bean实体暴露出来,以防止在属性注入过程中所注入的bean又依赖当前的bean造成的类似"死锁"的状态
但是存在以下情况,Spring依旧会陷入循环依赖死锁:
- 显式设置dependsOn的循环依赖
|
|
- 构造函数循环依赖
|
|
- factory-method循环依赖
|
|
- 上述三种依赖混合
只要一个循环依赖中的所有bean,其依赖关系都需要在创建bean实例之前进行解决,此循环依赖则一定无解
要打破无解的循环依赖,在构成循环依赖的一个环中,只需要保证其中至少一个Bean的依赖在该Bean创建且暴露earlySingleton之后处理即可,即在属性注入阶段进行属性依赖的处理
|
|
以"bean创建且暴露earlySingleton"为节点,在此之前处理依赖的有instance supplier parameter
、factory method parameter
、constructor parameter
、等,在此之后处理的依赖有 class property
、setter parameter
等
ApplicationContext
BeanFactory实现了IoC的基础能力,而ApplicationContext是BeanFactory的子类,除了继承IoC的基础能力外
- 支持国际化 (MessageSource)
- 支持资源访问 (ResourcePatternResolver)
- 事件机制 (ApplicationEventPublisher)
- 默认初始化所有Singleton
- 提供扩展能力
无论何种功能的ApplicationContext,在做完基本的初始化后均会调用AbstractApplicationContext#Refresh
AbstractApplicationContext#Refresh
准备上下文 - AbstractApplicationContext#prepareRefresh
该部分主要实现对上下文的准备工作,其主要涉及到两个接口AbstractApplicationContext#initPropertySources及ConfigurablePropertyResolver#validateRequiredProperties,前者由子类实现,用于初始化PropertySource;后者用于对必要属性进行验证
|
|
重写initPropertySources方法,并添加runtimeEnv为必须的环境变量属性,如此在系统启动的时候便会进行检测,对于不存在任何一个必要环境变量的情况均会抛出异常终止启动
加载BeanFactory - AbstractApplicationContext#obtainFreshBeanFactory
该函数内部实现比较简单,重点在refreshBeanFactory,该函数同样由子类实现
对于AbstractRefreshableApplicationContext,refreshBeanFactory基本步骤为
- 创建BeanFactory (DefaultListableBeanFactory)
- 设置BeanFactory
- 加载BeanDefinition
在第3步中,AbstractXmlApplicationContext的实现则是对xml配置文件的解析及加载;AnnotationConfigWebApplicationContext的实现则是对class文件的扫描并加载,以及其他基于AbstractRefreshableApplicationContext的ApplicationContext实现
对于GenericApplicationContext,BeanFactory的创建及BeanDefinition的加载在refresh调用之前早已完成,refreshBeanFactory的实现则是对BeanFactory加载状态的简单校验
AbstractRefreshableApplicationContext & GenericApplicationContext
AbstractRefreshableApplicationContext
对于继承自 AbstractRefreshableApplicationContext
的上下文,例如 ClassPathXmlApplicationContext
或 AnnotationConfigApplicationContext
,它们通过覆盖 refreshBeanFactory()
方法来实现具体的 BeanDefinition 加载逻辑。这些上下文类型专门用于从外部资源(如 XML 文件、Java 配置类等)加载配置信息,并将这些配置信息解析为一组 BeanDefinition,然后注册到内部的 BeanFactory 中。这个过程通常发生在上下文的 refresh()
方法调用过程中(我们正在讨论的),这个方法不仅负责加载和注册 BeanDefinition,还包括初始化单例bean、处理别名定义、注册BeanPostProcessor等一系列容器启动时的活动。
[!QUOTE] refresh()关键步骤 ^configurerRelated
- 创建 BeanFactory:
AbstractRefreshableApplicationContext
首先会创建一个新的BeanFactory
实例,这通常是一个DefaultListableBeanFactory
实例。这个BeanFactory
实现了BeanDefinitionRegistry
接口,使得它能够注册 BeanDefinition。- ==加载 BeanDefinition:接着,上下文会调用特定的方法(例如,对于基于 XML 的配置,会使用
XmlBeanDefinitionReader
;对于基于注解的配置,会使用AnnotatedBeanDefinitionReader
和ClassPathBeanDefinitionScanner
)来加载 BeanDefinition。这些 Reader 和 Scanner 实现了BeanDefinitionRegistry
接口的registerBeanDefinition
方法来实际完成注册工作。==- 刷新 BeanFactory:加载完所有 BeanDefinition 后,
AbstractRefreshableApplicationContext
会对BeanFactory
进行刷新,这涉及到预实例化单例、注册BeanPostProcessor
、初始化剩余的非懒加载单例等一系列操作。- 发布事件:在整个容器刷新过程中,还会发布各种应用事件,如
ContextRefreshedEvent
,允许应用中的其他组件对这些事件作出响应。通过上述步骤,
AbstractRefreshableApplicationContext
完成了 BeanDefinition 的加载、注册以及整个 Spring 容器的初始化和刷新工作。在这个过程中,BeanDefinitionRegistry
接口扮演了 BeanDefinition 注册的关键角色GenericApplicationContext
GenericApplicationContext
直接实现了 BeanDefinitionRegistry
接口,使得它可以在运行时动态注册 BeanDefinition。与 AbstractRefreshableApplicationContext
的子类不同,GenericApplicationContext
并不专门依赖于外部资源来加载 BeanDefinition。相反,它提供了一套程序化的接口,允许开发者直接在代码中通过调用 registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
方法来注册 BeanDefinition。这种方式使得 GenericApplicationContext
非常灵活,适用于那些需要在运行时动态调整 Spring 配置的场景。
关系和区别
- 加载方式的区别:
AbstractRefreshableApplicationContext
的子类通常通过解析配置资源(XML、注解等)来加载 BeanDefinition,而GenericApplicationContext
允许以编程方式直接注册 BeanDefinition。 - 使用场景的区别:
AbstractRefreshableApplicationContext
的子类适合于静态配置资源的场景,其中配置信息在应用启动时已经确定。GenericApplicationContext
更适合于动态配置的场景,比如基于条件的 BeanDefinition 注册或运行时的配置调整。 - 刷新容器的能力:虽然两者都可以通过
refresh()
方法来刷新应用上下文,但AbstractRefreshableApplicationContext
的子类通常在设计时就考虑了完整的容器刷新流程(包括重新加载配置资源),而GenericApplicationContext
刷新主要是为了应用新注册的 BeanDefinition。==前者会重置BeanFactory而后者不会==
填充部分扩展 - AbstractApplicationContext#prepareBeanFactory
该函数执行以下逻辑
- 设置BeanFactory的ClassLoader
- 注册默认BeanExpressionResolver,用于依赖注入时SpEL的支持
- 注册默认PropertyEditor,用于依赖注入时对参数的解析转换
- 注册几个特殊Aware的处理逻辑
- 注册AspectJ相关的几个处理器,用于AOP的支持
- 注册几个特殊的BeanDefinition
==2-3 的核心逻辑在于解析依赖的值,DefaultListableBenFactory#doResolveDependency
==
注册几个特殊Aware的处理逻辑
在Bean实例化、注入依赖之后会对Bean进行[最后的初始化](#初始化 - AbstractAutowireCapableBeanFactory initializeBean
“wikilink”),调用相应的setter方法分别针对BeanNameAware、BeanClassLoaderAware、BeanFactoryAware进行处理
在该函数中,会注册几个特殊的BeanPostProcessor
|
|
其实现了postProcessBeforeInitialization方法,内部调用ApplicationContextAwareProcessor#invokeAwareInterfaces针对另外的几类Aware进行了处理
除此之外,Spring会将上述几类Aware设置为ignoreDependencyInterface,这意味着以上几类Bean的注入只能通过Aware的方式而不能通过其他属性依赖注入的方式(属性注入、函数参数注入等)
注册特殊的Bean
在使用Spring时,是否有过直接注入BeanFactory亦或是ResourceLoader,这些bean正是在这里被Spring注册进去的,除以上外Spring还注入了
- BeanFactory
- ResourceLoader
- ApplicationEventPublisher
- ApplicationContext
- Environment
- systemProperties - Environment#.getSystemProperties:Map<String, Object>
- systemEnvironment - Environment#.getSystemEnvironment:Map<String, Object>
AbstractApplicationContext#refresh#postProcessBeanFactory()
对于不同的实现类,注册相应的BeanPostProcessor
,例如ServletWebServerApplicationContext
激活BeanFactoryPostProcessor - AbstractApplicationContext#invokeBeanFactoryPostProcessors
其内部实现在PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
BeanFactoryPostProcessor的定义非常简单,其postProcessBeanFactory方法允许在bean实例化前对BeanFactory做一些额外的设置
|
|
核心逻辑如下
其中涉及两种类型,BeanDefinitionRegistryPostProcessor及BeanFactoryPostProcessor,前者为后者的子类,BeanDefinitionRegistryPostProcessors提供了额外的接口postProcessBeanDefinitionRegistry,用于更加方便地动态地注册额外的BeanDefinition (registryProcessor.postProcessBeanDefinitionRegistry(registry)
),如读取配置文件(json、properties、yml)并解析(或者任何其他的形式),并通过该接口注册相应的BeanDefinition,基于Spring Boot Starter的很多框架均使用该方式进行bean的注册
以上流程图可以看出,优先执行BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry,再执行BeanFactoryPostProcessor#postProcessBeanFactory,各自内部优先执行PriorityOrdered实现,再执行Ordered实现,最后执行无任何排序的实现
注册BeanPostProcessor - AbstractApplicationContext#registerBeanPostProcessors
其内部实现在PostProcessorRegistrationDelegate#registerBeanPostProcessors b
BeanPostProcessor
|
|
- postProcessBeforeInitialization方法在调用bean的init-method之前执行
- postProcessAfterInitialization方法在调用bean的init-method之后执行
- 任何一个方法可对现有bean实例做进一步的修改
- 任何一个方法可返回新的bean实例,用来替代现有的bean实例
第四点即是AOP生成当前Bean代理的方法
InstantiationAwareBeanPostProcessor
该接口继承自BeanPostProcessor,其同样有两个方法,一个在创建bean实例之前调用([createBean](#AbstractAutowireCapableBeanFactory createBean
“wikilink”)),一个在创建bean实例之后、属性注入之前调用([属性注入](#属性注入 - AbstractAutowireCapableBeanFactory populateBean
“wikilink”))
|
|
AbstractApplicationContext#registerBeanPostProcessors,其内部逻辑与BeanFactoryPostProcessor的注册逻辑类似:
- 找到所有BeanPostProcessor并实例化
- 按照实现的Ordered接口分别放入priorityOrderedPostProcessors、orderedPostProcessors、nonOrderedPostProcessors并各自排序
- 如果实现了MergedBeanDefinitionPostProcessor则放入internalPostProcessors并排序
- 按顺序依次注册priorityOrderedPostProcessors、orderedPostProcessors、nonOrderedPostProcessors
- 最后注册internalPostProcessors
MergedBeanDefinitionPostProcessor其有一个接口postProcessMergedBeanDefinition,在bean实例化完成后属性注入之前被调用,可以用来对当前的BeanDefinition做进一步的修改,如增加PropertyValue等,实现特殊的属性依赖注入,参考[BeanDefinition后处理](#BeanDefinition后处理 - AbstractAutowireCapableBeanFactory applyMergedBeanDefinitionPostProcessors
“wikilink”)与[属性注入](#属性注入 - AbstractAutowireCapableBeanFactory populateBean
“wikilink”)
初始化MessageSource - AbstractApplicationContext#initMessageSource
Spring的MessageSource提供了国际化能力,在开发者未注册MessageSource的情况下Spring会提供一个默认的DelegatingMessageSource
初始化ApplicationEventMulticaster - AbstractApplicationContext#initApplicationEventMulticaster
Spring提供了一套事件(ApplicationEvent)的发布&订阅机制,开发者可自定义事件(继承ApplicationEvent),注册事件监听器来订阅消费事件(实现ApplicationListener 或使用@EventListener
注解),并使用ApplicationEventPublisher(直接依赖注入或者使用ApplicationEventPublisherAware)发送事件,使用示例可参考https://www.baeldung.com/spri…
其实ApplicationContext实现了ApplicationEventPublisher,跟踪其publishEvent方法会发现,最终调用了AbstractApplicationContext#applicationEventMulticaster.multicastEvent,开发者可以自行注册一个ApplicationEventMulticaster,如果没有Spring会提供一个默认的SimpleApplicationEventMulticaster
SimpleApplicationEventMulticaster#multicastEvent的逻辑比较简单,会根据事件的类型找到可以处理的所有ApplicationListener,依次调用它们的onApplicationEvent方法消费事件
|
|
默认情况下会同步、顺序的调用listeners的onApplicationEvent方法,只有设置了executor才会异步调用,不过这样的控制粒度比较粗,要么全部同步消费要么全部异步消费,比较细粒度的控制事件的消费有几种常用方法
- 使用@Async注解,独立控制某一listener异步消费(https://www.baeldung.com/spri…)
- 自行编码,将onApplicationEvent逻辑放在线程中执行
- 注册自定义的ApplicationEventMulticaster,内部实现自己的同步、异步Event处理逻辑
注册ApplicationListener - AbstractApplicationContext#registerListeners
这里的逻辑比较简单
- 在BeanFactory中找到ApplicationListener类型的bean并实例化
- 调用ApplicationEventMulticaster#addApplicationListenerBean方法将ApplicationListeners注册进去
初始化所有非Lazy Bean - AbstractApplicationContext#finishBeanFactoryInitialization
对于Singleton Bean而言,实例化发生在首次getBean,但你是否有疑惑,我们只是注册了众多Singleton Bean,但在Spring初始化完成后所有的Singleton Bean(Lazy Bean除外)均已经完成实例化
回到AbstractApplicationContext#finishBeanFactoryInitialization,该函数会实现几个逻辑
- 如果自定义了ConversionService(另一种注入类型转换的方式)类型bean且bean-name为conversionService,则将其注册到BeanFactory中
- 如果BeanFactory中不存在EmbeddedValueResolver(PropertyResourceConfigurer会注册一个PlaceholderResolvingStringValueResolver到BeanFactory中),则会注册一个默认的StringValueResolver用来处理
${ ... }
类型的值(Environment#resolvePlaceholders) - 找到所有非Lazy的Singleton BeanDefinition进行实例化(getBean)
- 如果是FactoryBean,则在bean name前加上’&’,并实例化该FactoryBean,随后实例化真实的bean
- 如果不是FactoryBean,则直接实例化该bean
- 执行SmartInitializingSingleton实现类的afterSingletonsInstantiated方法
Refresh的后续动作 - AbstractApplicationContext#finishRefresh
除了一些中间状态需要清理外,还有两件比较特殊的地方
LifecycleProcessor - AbstractApplicationContext#initLifecycleProcessor
Spring提供了LifecycleProcessor用于监听BeanFactory的refresh及close,在BeanFactory的各阶段会调用LifecycleProcessor的onFresh及onClose方法
开发者可以自行注册LifecycleProcessor类型的bean,bean-name必须为"lifecycleProcessor",否则Spring会提供一个默认的DefaultLifecycleProcessor
之后则会触发LifecycleProcessor的onFresh方法
除此之外,还可以监听ContextRefreshedEvent及ContextClosedEvent消息
refresh事件
在BeanFactory初始化完成后,则会发出ContextRefreshedEvent事件
BeanFactory的销毁 - AbstractApplicationContext#registerShutdownHook
该函数用来注册BeanFactory的销毁逻辑
|
|
其直接使用了java的addShutdownHook函数,在jvm进程正常退出的时候触发
AbstractApplicationContext#doClose函数定义了BeanFactory具体的销毁过程
- 发出ContextClosedEvent事件
- 触发LifecycleProcessor的onClose方法
- 销毁bean,细节参考Bean销毁过程
- 由子类实现的AbstractApplicationContext#closeBeanFactory及AbstractApplicationContext#onClose方法
ASIDE
- BeanDefinition的加载在[AbstractApplicationContext#obtainFreshBeanFactory](#加载BeanFactory -
AbstractApplicationContext obtainFreshBeanFactory
“wikilink”)中实现 - TODO
#{ ... }
类型值的解析由StandardBeanExpressionResolve实现${ ... }
类型值的解析由PlaceholderResolvingStringValueResolver实现- Spring提供了众多默认的PropertyEditor,若需要自定义PropertyEditor可以通过注册CustomEditorConfigurer实现
- Spring提供了众多Aware,若需要自定义Aware可以通过BeanPostProcessor实现
- BeanFactoryPostProcessor用于在实例化bean之前对BeanFactory做额外的动作 如,PropertyResourceConfigurer用来将PlaceholderResolvingStringValueResolver注册到BeanFactory的embeddedValueResolvers中
- [BeanDefinitionRegistryPostProcessor](#激活BeanFactoryPostProcessor -
AbstractApplicationContext invokeBeanFactoryPostProcessors
“wikilink”)用于在实例化bean之前(动态)注册额外的BeanDefinition ^fa1ce8 - BeanPostProcessor用于在调用bean的init-method前后,对实例化完成的bean做一些额外的干预 如,CommonAnnotationBeanPostProcessor用来处理@PostConstructor,AbstractAdvisingBeanPostProcessor用来实现AOP
ApplicationContext具体实现类 - AnnotationConfigApplicationContext
|
|
无参构造
|
|
AnnotatedBeanDefinitionReader
|
|
这里会将ConfigurationClassPostProcessor后置处理器加入到BeanFactory中,它继承自BeanFactoryPostProcessor,也就是说一会会在BeanFactory初始化完成之后进行后置处理,同时这里也会注册一个AutowiredAnnotationBeanPostProcessor后置处理器到BeanFactory,它继承自BeanPostProcessor,用于处理后续生成的Bean对象,其实看名字就知道,这玩意就是为了处理@Autowire、@Value这种注解,用于自动注入
注册传入的配置类 - register
|
|
[Refresh](#AbstractApplicationContext Refresh
“wikilink”)
==TODO==
- ☒ Spring AOP
- ☐ 注解运行逻辑
@Component
与@Bean
的区别- JavaSSM#^473168
- ☐ @Bean 在处理属性注入时?
- ☒ AnnotationConfigApplicationContext - 与 配置类的关系 - 具体例子
- ☐ BeanDefinitionReader和BeanDefinitionRegistry
- ☐ 完善调用链图
配置类的注册 -
ConfigurationClassPostProcessor
ConfigurationClassPostProcessor继承自BeanDefinitionRegistryPostProcessor -> BeanFactoryPostProcessor,这个后置处理器是Spring中提供的,这是专门用于处理配置类的后置处理器,其中ImportBeanDefinitionRegistrar
,还有ImportSelector
都是靠它来处理
ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
内部调用 processConfigBeanDefinitions(BeanDefinitionRegistry) 方法
|
|
ConfigurationClassParser#parse(candidates)
|
|
内部遍历candidates中的每一个BeanDefinitionHolder,调用parse的多态方法,最终调用ConfigurationClassParser#processConfigurationClass
,最后调用deferredImportSelectorHandler.process()
处理DeferredImportSelector相关的Bean注册 ^processConfigurationClass
首先判断条件注释,即处理@Conditional
相关注解
然后将不同来源的配置类源信息通过asSourceClass
进行封装,交给最核心的调用[doProcessConfigurationClass](#ConfigurationClassParser doProcessConfigurationClass
“wikilink”)
将配置类
ConfigurationClass
实例化为SourceClass
。这样做的目的是为了让后续的处理逻辑能够通过SourceClass
访问到配置类中定义的所有相关信息(比如注解信息,Meta-info),并进行相应的处理。例如,通过SourceClass
可以读取配置类上的@ComponentScan
注解,并执行组件扫描;读取@Import
注解,并处理导入的配置类或组件;读取@Bean
方法,并注册对应的Bean定义等。
ConfigurationClassParser#doProcessConfigurationClass
|
|
该函数依次解决如下问题:
- 处理@Component注解
- 处理@PropertySource和@PropertySources注解
- 处理@ComponentScan和@ComponentScans
- 处理@Import注解
- 处理@ImportResource注解
- 处理@Bean注解的方法
- 处理接口上的默认方法和超类
其中的核心是处理@Import
注解,通过调用 [ConfigurationClassParser#processImports](#ConfigurationClassParser processImports
“wikilink”)
ConfigurationClassParser#processImports
注意其第三个入参Collection<SourceClass> importCandidates
,它是通过调用getImports(sourceClass)
方法,从给定的sourceClass
中提取所有@Import
注解指定的类,如果sourceClass是普通的配置类,直接通过isEmpty()
返回
|
|
代码遍历每一个@Import
注解指定的候选类,根据不同类型进行处理
ImportSelector
实现ImportSelector
DeferredImportSelector
ImportBeanDefinitionRegistar
实现- 普通的配置类
针对ImportSelector
通过selector.selectImports()
与asSourceClasses()
方法将需要导入的类重新封装为SourceClass
,递归调用processImports
针对DeferredImportSelector
通过调用ConfigurationClassParser
的内部类DeferredImportSelectorHandler#handle()
方法,将其封装为DeferredImportSelectorHolder
,加入待处理的List - deferredImportSelectors
在ConfigurationClassParser#parse
[处理完所有候选配置类后](#ConfigurationClassParser parse(candidates)
“wikilink”),调用DeferredImportSelectorHandler#process()
方法,该方法将加入deferredImportSelectors
中的所有DeferredImportSelectorHolder
执行内部类的DeferredImportSelectorGroupingHandler#register
方法,得到包装好的、已经分组完毕的DeferredImportSelectorGrouping
,然后调用DeferredImportSelectorGroupingHandler#processGroupImports()
,处理组内所有的延迟导入 (DeferredImportSelector
)
DeferredImportSelectorGroupingHandler#register
|
|
- 首先尝试获取
DeferredImportSelector
指定的导入组 (ImportGroup
),如果没有指定特定的导入组,则使用DeferredImportSelector
本身作为组的Key - 尝试从一个名为
groupings
的映射中获取或创建一个与导入组对应的DeferredImportSelectorGrouping
对象。如果映射中尚未存在与当前组对应的分组,那么将创建一个新的分组,并将其加入到映射中- 注意,此处的Group逻辑是将
DeferredImportSelector.Group
这个内部接口包装到ConfigurationClassParser.DeferredImportSelectorGourping
这个内部类中,其内部维护了一个DeferredImportSelector.Group
对象和List<DeferredImportSelectorHolder>
对象
- 注意,此处的Group逻辑是将
- 调用
DeferredImportSelectGrouping#add(DeferredImportSelectorHolder)
,将DeferredImportSelectorHolder
加入内部类维护的Grouping
中 (静态类) - 最后,代码将当前
DeferredImportSelectorHolder
对应的配置类(ConfigurationClass
)及其元数据添加到一个名为configurationClasses
的映射中。这确保了后续能够快速访问到与特定DeferredImportSelector
相关联的配置类
DeferredImportSelectorGroupingHandler#processGroupImports
|
|
- 遍历保存在
Groups - DeferredImportSelectorGroupingHandler
中的DeferredImportSelectorGroup
对象,调用DeferredImportSelectorGroup#getImports()
方法 DeferredImportSelectorGroup#getImports()
方法调用DeferredImportSelectorGroup
中维护的真实的Group -DeferredImportSelector.Group#process
方法,然后返回含有meta-info
的Entry
- 使用内部维护的
Map
(在register
中put),根据Entry.meta-info
得到对应的ConfigurationClass
,调用ConfigurationClassParser#processImports
,和[前面](#ConfigurationClassParser processImports
“wikilink”)一样递归调用进行处理
所以根据以上分析,DeferredImportSelector
最终的处理逻辑在于DeferredImportSelector.Group#process()
^db8805
针对ImportBeanDefinitionRegistar
|
|
调用ConfigurationClass#addImportBeanDefinitionRegistrar
方法,将对应的实例加入configClass对应的Collection类中,后续在[loadBeanDefinitions](#ConfigurationClassBeanDefinitionReader loadBeanDefinitions
“wikilink”)中调用其registerBeanDefinitions
,注册相应的BeanDefinition
针对普通配置类
不使用特殊机制,直接递归调用processConfigurationClass
ConfigurationClassParser#getConfigurationClasses
返回从前面得到的所有待配置的配置类
ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
^98f726
|
|
通过遍历每一个配置类,调用loadBeanDefinitionsForConfigurationClass
方法 ^f6a27a
- registerBeanDefinitionForImportedConfigurationClass(configClass) 注册配置类自身
- loadBeanDefinitionsForBeanMethod(beanMethod) 注册@Bean注解标识的方法
- loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); 注册@ImportResource引入的XML配置文件中读取的bean定义
- loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); 注册configClass中经过解析后保存的所有ImportBeanDefinitionRegistrar,注册对应的BeanDefinition
AOP
AOP的实现类是AnnotationAwareAspectJAutoProxyCreator
,其是BeanPostProcessor
的实现类,具体来说,是InstantiationAwareBeanPostProcessor
的实现类,在实例化Bean过程中,通过调用BeanPostProcessor中的实例化前处理器进行短路,得到相应的代理Bean
@EnableAspectJAutoProxy
|
|
这个注解使用@Import
导入了AspectJAutoProxyRegistrar
,其是ImportBeanDefinitionRegistrar
的实现类,会在处理配置类相应@Import
机制的时候将AnnotationAwareAspectJAutoProxyCreator
实现类注册到容器中,即注册到BeanDefinition中,实现相应的实例化前处理器功能 (InstantiationAwareBeanPostProcessor
)