@RefreshScope(nacos配置熱更新方式)
@RefreshScope(nacos配置熱更新)

源碼分析
宏觀流程解析
1.spring對@RefreshScopre注解的bean做的事情
- 當(dāng)調(diào)用被@RefreshScope注解的bean的屬性的get方法時 則先從本地緩存里面獲取
- 當(dāng)本地緩存中 不存在當(dāng)前bean時 則重新創(chuàng)建 此時 會獲取 spring中最新環(huán)境配置
- 如果本地緩存中 存在當(dāng)前 bean則 直接返回對應(yīng)屬性值
2.nacos對@RefreshScopre注解的bean做的事情
- 當(dāng)配置更改時 nacos服務(wù)端會發(fā)步一個配置已被更新事件
- 此時 naocs客戶端 會接受到這個事件 接受到以后 會再在spring中發(fā)布環(huán)境配置刷新事件
- 然后 對應(yīng)的監(jiān)聽器 收到以后 則刷新spring環(huán)境配置 以及 清空本地緩存
源碼解析
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {
/**
* @see Scope#proxyMode()
* @return proxy mode
*/
ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan

org.springframework.context.annotation.AnnotationConfigUtils#applyScopedProxyMode -->org.springframework.context.annotation.ScopedProxyCreator#createScopedProxy -->org.springframework.aop.scope.ScopedProxyUtils#createScopedProxy

org.springframework.cloud.context.scope.GenericScope#postProcessBeanDefinitionRegistry

org.springframework.cloud.context.scope.GenericScope.LockedScopedProxyFactoryBean#setBeanFactory

org.springframework.aop.scope.ScopedProxyFactoryBean#setBeanFactory
創(chuàng)建代理



------由上可知,被@RefreshScope注解的bean被包裝為一個
FactoryBean(org.springframework.cloud.context.scope.GenericScope.LockedScopedProxyFactoryBean)
由此調(diào)用時就會調(diào)用getObject()方法,這樣就會得到一個代理對象,執(zhí)行時會獲取到目標(biāo)對象 SimpleBeanTargetSource.getTarget(),以"scopedTarget."開頭的bean,接下來看一下該bean的創(chuàng)建時機
創(chuàng)建target
org.springframework.cloud.context.scope.refresh.RefreshScope#onApplicationEvent

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

org.springframework.cloud.context.scope.GenericScope#get


以上即@RefreshScope的相關(guān)對象的創(chuàng)建
由上可知,目標(biāo)類都會存于scope的cache里
NacosContextRefresher(nacos配置刷新)
public class NacosContextRefresher
implements ApplicationListener<ApplicationReadyEvent>, ApplicationContextAware
{
public void onApplicationEvent(ApplicationReadyEvent event) {
// many Spring context
if (this.ready.compareAndSet(false, true)) {
this.registerNacosListenersForApplications();
}
}
}com.alibaba.cloud.nacos.refresh.NacosContextRefresher#registerNacosListenersForApplications --->com.alibaba.cloud.nacos.refresh.NacosContextRefresher#registerNacosListener
注冊監(jiān)聽器,監(jiān)聽nacos配置變化,并發(fā)布RefreshEvent

org.springframework.cloud.endpoint.event.RefreshEventListener#onApplicationEvent

org.springframework.cloud.context.refresh.ContextRefresher#refresh
1.刷新了環(huán)境,2清空cache

首先刷新環(huán)境

如下,有個前后對比,關(guān)鍵就在addConfigFilesToEnvironment()

首先copyEnvironment,雖說是copy,這里只保留了一些最基本的配置,如下

第二步,創(chuàng)建Spring容器 capture = builder.run();
這里還是走之前的邏輯,具體可參考
只是這次創(chuàng)建的兩個Spring容器都為AnnotationConfigApplicationContext,并且用完就關(guān)了
我們看一下方法執(zhí)行之后的environment

之后的邏輯就是對比兩個環(huán)境進行替換了,這就是刷新環(huán)境的大致流程
然后清空cache


總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot靜態(tài)資源映射規(guī)則淺析
這篇文章主要介紹了SpringBoot靜態(tài)資源映射規(guī)則,今天在玩SpringBoot的demo的時候,放了張圖片在resources目錄下,啟動區(qū)訪問的時候,突然好奇是識別哪些文件夾來展示靜態(tài)資源的, 為什么有時候放的文件夾不能顯示,有的卻可以2023-02-02
SpringBoot 啟動報錯Unable to connect to 
這篇文章主要介紹了SpringBoot 啟動報錯Unable to connect to Redis server: 127.0.0.1/127.0.0.1:6379問題的解決方案,文中通過圖文結(jié)合的方式給大家講解的非常詳細,對大家解決問題有一定的幫助,需要的朋友可以參考下2024-10-10
Spring定時任務(wù)輪詢本地數(shù)據(jù)庫實現(xiàn)過程解析
這篇文章主要介紹了Spring定時任務(wù)輪詢本地數(shù)據(jù)庫實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-01-01

