背景
前面我们知道,被 @RefreshScope
注解的实例,在扫描生成 BeanDefiniton
时,被偷龙转凤了:注册了两个 Bean 定义,一个 beanName 同名、类型是 LockedScopedProxyFactoryBean.class
代理工厂 Bean,一个 scopedTarget.beanName
的目标 Bean。
当程序使用 getBean
获取一个被 @RefreshScope
注解的实例时,容器返回的是一个JdkDynamicAopProxy
代理对象, 它是怎么从 ScopedProxyFactoryBean
创建的呢?本文记录这个过程的跟踪流程。
代理类的创建
首先,从 spring 的抽象 Bean 工厂类 AbstractApplicationContext
开始,当 getBean(type)
调用时,开启 Bean 工厂生产的流程:
接着,它背后是 DefaultListableFactoryBean
,开始干活,resolveBean
返回需要的 Bean 实例:
继续跟resolveNamedBean
,定位到背后的 Bean Definition :
注意,这里在查找候选类型的时候,由于扫描时注入了两个相同类型的 Bean
注意这里,还记得吗,代理类和委托类类型相同,candidateNames 返回了两个名称 beanName 和 scopedTarget.beanName
,但是真正委托类的属性被修改了,这里只会得到一个名称:
一路委托调用:
终于到了真正干活的地方 doGetBean
:
- 先查找 beanName 所在的单例对象,实际就是
ScopedProxyFactoryBean
对象; - 接着调用
getObjectForBeanInstance
创建实例。
核心代码到了,DefaultSingletonBeanRegistry.getSingleton
,它开始查找 beanName
所在的单例工厂:
接着回到 AbstractBeanFactory.getObjectForBeanInstance
开始从单例工厂创建实例:
因为前一步取到的是 ScopedProxyFactoryBean
的实例是一个 FactoryBean
,所以直接进入最后一个分支:
doGetObjectFromFactoryBean
调用 ScopedProxyFactoryBean.getObject
:
所以这个调用链,最终返回了 ScopedProxyFactoryBean
在被注入 BeanFactory
时创建的那个 proxy
代理类:
启示录
当程序使用 getBean
获取一个被 @RefreshScope
注解的实例时,最终得到的是 LockedScopedProxyFactoryBean
的 getObject()
返回值,它是一个 JdkDynamicAopProxy
代理对象。
中间对 ScopedProxyFactoryBean
初始化的流程,含有很多细节,比如 GenericScope
注册的 BeanDefinitionRegistryPostProcessor
对代理 Bean 定义添加了一个构造函数的参数,它是怎么在 LockedScopedProxyFactoryBean
初始化时使用的。
还有 AbstractAutowiredCapableBeanFactory
的织入回调 invokeAwareMethod
,BeanDefinitionRegistryPostProcessor
回调等,水不知几深,浅尝辄止尔!
参考
看到一篇很完整的文章,可以参考补充:《SpringCloud @RefreshScope动态刷新配置原理浅析》