Spring Cloud @RefreshScope 原理分析:扫描 Bean 定义
Posted 毕小宝
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Cloud @RefreshScope 原理分析:扫描 Bean 定义相关的知识,希望对你有一定的参考价值。
背景
最近读了一下 spring cloud 的 @RefreshScope
生效的源码,总结一下该注解的 refresh
类型的类实例化的过程。
关键技术点:
- 扫描过程中对
@RefreshScope
注解做了特殊处理,会额外注册两个BeanDefinition
。 GenericScope
实现了BeanDefinitionRegistryPostProcessor
接口,并对 refresh 的BeanDefinition
添加了构造函数参数为自己,同时设置 beanClass 属性为GenericScope.LockedScopedProxyFactoryBean.class
,合成属性为true
。GenericScope.LockedScopedProxyFactoryBean
类实现了FactoryBean
、BeanFactoryAware
、MethodInterceptor
接口。
拆解三个部分:扫描 Bean 定义、代理类实例化、代理类方法调用,从这三个过程的源码,来理解为什么 @RefreshScope
标注的类的实能够动态应对环境变量的变化。
原始扫描 Bean 定义过程
ClassPathBeanDefinitionScanner
扫描时会对 @RefreshScope
注解的类的 BeanDefinition
定义信息作两个操作:
这个 applyScopedProxyMode
方法判断当前代理模式,如果
而 @RefreshScope
的这个属性是 ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS
,即针对这类注解的类在扫描时,会额外创建代理类的 BeanDefinition
:
主要是三个操作:
- 以原始的
BeanDefinition
新建一个代理类的RootBeanDefinition
,并且设置它的decoratedDefinition
为原始对象,代理类的类型为ScopedProxyFactoryBean
; - 再注册一个以
"scopedTarget." + originalBeanName
,基于原始配置的目标定义,即真正实体的定义修改了; - 最后再注册一个用
originalBeanName
的代理类的定义,就是偷梁换柱,完全代理了目标对象。 - 原始类定义的
autowireCandidate
为 false ,primary
也为 false ,那么就能保证实力获取时优先找到的候选对象是代理对象。
GenericScope 增强注册
GenericScope
实现了 BeanDefinitionRegistryPostProcessor
接口,而且它 Order 优先级较低,保证在 第一步的扫描之后执行如下操作:
这里对扫描阶段创建的代理类的 BeanDefinition
作了三个增强:
- 修改代理的
BeanDefinition
类型为自己的LockedScopedProxyFactoryBean
; - 为代理类的
BeanDefinition
添加一个构造函数的参数值为自己,因为LockedScopedProxyFactoryBean
类的构造函数需要一个入参Scope
; - 设置合成属性为真。
启示录
@RefreshScope
是 spring cloud 的技术,它本质上扩展了 spring 框架的 Scope,跟其他单例、原型、请求类型、会话类型一样,是一种扩展 Scope ,巧妙应用了 ScopedProxyMode.TARGET_CLASS
和 AOP ,把 refresh 类型的对象托管起来,保证环境变量变更时,销毁旧的实例、获取最新的实例。
下一篇讲继续总结 ScopedProxyFactoryBean
这个类是如何创建出 @RefreshScope
注解的实例的,为什么能将一个委托类型偷梁换柱为一个 JdkDynamicAopProxy
代理类。
以上是关于Spring Cloud @RefreshScope 原理分析:扫描 Bean 定义的主要内容,如果未能解决你的问题,请参考以下文章
Spring Cloud实战Spring Cloud GateWay服务网关
spring-cloud-config——Quick Start
Spring Cloud入门 - Spring Cloud保护机制