动态配置刷新原理@RefreshScope
type
status
date
slug
summary
tags
category
icon
password
请注意,该文章主题是:当配置中心配置发生变化,且已告知应用程序后(1),应用程序在获取到新配置后如何更新内存中已加载的配置并使用的原理(2)。
并非(1)中如何知道(监听)配置改变的原理,切勿和Spring Cloud Bus、Spring Cloud Config(或者nacos)配置刷新(实际上是监听配置发生改变)的原理搞混了。
前言
在Spring Cloud中,@RefreshScope注解可以用于动态刷新配置。该注解可以标记Spring Bean,使其在配置发生变化时得到更新。
在实际应用场景中,我们可能会修改配置文件中的某些参数,例如数据库连接信息、Redis缓存配置等,但是这些参数对应的Bean并不会随之更新。为了解决这个问题,我们可以使用@RefreshScope注解。
当我们在配置中心修改了配置后,通过发送POST请求到/actuator/refresh端点,Spring会自动重新加载所有标记了@RefreshScope注解的Bean。这样我们就可以在不重启应用的情况下更新我们的配置。
需要注意的是,@RefreshScope注解只适用于Spring Boot 2.4及以上版本。在早期版本中,我们需要手动注入RefreshScope并使用refresh()方法来刷新配置。
总之,使用@RefreshScope注解可以让我们在不重启应用的情况下更新配置。这对于实时性要求较高的应用非常有用。
总览
和动态配置刷新有关的类和注解如下:
- @Scope
- @RefreshScope
- RefreshScope
- GenericScope
- Scope
- ContextRefresher
@RefreshScope

@RefreshScope注解中关键的注解是@Scope,这个注解常用于配置bean的作用域。

关键是proxyMode这个变量。当其值为ScopedProxyMode .TARGET_CLASS 的时候会给当前创建的bean 生成一个代理对象,会通过代理对象来访问,每次访问都会创建一个新的对象。而@RefreshScope注解中proxyMode的默认值就为TARGET_CLASS。
@Scope
对于scope中代理对象的生成和获取原理,见Scope接口:
关键是这个get方法,通过这个方法会创建并返回新的代理对象来进行访问。
@RefreshScope在调用刷新的时候会使用此方法来给我们创建新的对象,这样就可以通过spring的装配机制将属性重新注入了,也就实现了所谓的动态刷新。
RefreshScope类
这个类展示了具体的配置刷新原理,是怎么处理老的对象,又是怎么去创建新的代理对象。
RefreshScope继承了GenericScope,而GenericScope实现了Scope接口并实现了get(String name,ObjectFactory<?> objectFactory)方法。

在GenericScope 里面包装了一个内部类 BeanLifecycleWrapperCache,对加了@RefreshScope 注解的bean,在创建代理对象时对代理对象进行缓存,使其在不刷新时获取的都是同一个对象。(这里可以把 BeanLifecycleWrapperCache 想象成为一个大Map 缓存了所有@RefreshScope 标注的对象)。
知道了对象是缓存的,所以在进行动态刷新的时候,只需要清除缓存,重新创建就好了。
下面是关键代码:
ContextRefresher 就是外层调用方法用的,GenericScope 里面的 get 方法负责对象的创建和缓存,destroy 方法负责再刷新时缓存的清理工作。
总结
- 需要动态刷新的类标注@RefreshScope 注解;
- @RefreshScope 注解标注了@Scope 注解,并默认了ScopedProxyMode.TARGET_CLASS; 此属性的功能就是在创建一个代理,在每次调用的时候都用它来调用GenericScope get 方法来获取对象。
- 如属性发生变更会调用 ContextRefresher refresh() -》RefreshScope refreshAll() 进行缓存清理方法调用,并发送刷新事件通知 -》 GenericScope 真正的 清理方法destroy() 实现清理缓存。
- 在下一次使用对象的时候,会调用GenericScope get(String name, ObjectFactory<?> objectFactory) 方法创建一个新的对象,并存入缓存中,此时新对象因为Spring 的装配机制就是新的属性了。
扩展
nacos的配置中心,支持@RefreshScope注解。nacos内置的监听器在收到配置发生改变的通知后,通过上面的机制刷新配置,即发送
RefreshEvent 事件 →RefreshEventListener 触发监听 →ContextRefresher#refresh() →后续@RefreshScope的刷新逻辑- GitTalk