最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringCloud?@RefreshScope刷新機(jī)制淺析

 更新時間:2023年03月12日 10:49:25   作者:架構(gòu)核心技術(shù)  
RefeshScope這個注解想必大家都用過,在微服務(wù)配置中心的場景下經(jīng)常出現(xiàn),他可以用來刷新Bean中的屬性配置,那大家對他的實(shí)現(xiàn)原理了解嗎?它為什么可以做到動態(tài)刷新呢

一、前言

用過Spring Cloud的同學(xué)都知道在使用動態(tài)配置刷新的我們要配置一個@RefreshScope 在類上才可以實(shí)現(xiàn)對象屬性的的動態(tài)更新,本著知其所以然的態(tài)度,晚上沒事兒又把這個點(diǎn)回顧了一下,下面就來簡單的說下自己的理解。

總覽下,實(shí)現(xiàn)@RefreshScope 動態(tài)刷新的就需要以下幾個:

  • @ Scope
  • @RefreshScope
  • RefreshScope
  • GenericScope
  • Scope
  • ContextRefresher

二、@Scope

一句話,@RefreshScope 能實(shí)現(xiàn)動態(tài)刷新全仰仗著@Scope 這個注解,這是為什么呢?

@Scope 代表了Bean的作用域,我們來看下其中的屬性:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
	/**
	 * Alias for {@link #scopeName}.
	 * @see #scopeName
	 */
	@AliasFor("scopeName")
	String value() default "";
	/**
	 *  singleton  表示該bean是單例的。(默認(rèn))
     *  prototype    表示該bean是多例的,即每次使用該bean時都會新建一個對象。
     *  request        在一次http請求中,一個bean對應(yīng)一個實(shí)例。
     *  session        在一個httpSession中,一個bean對應(yīng)一個實(shí)例
	 */
	@AliasFor("value")
	String scopeName() default "";
	/**
    *   DEFAULT			不使用代理。(默認(rèn))
	* 	NO				不使用代理,等價于DEFAULT。
	* 	INTERFACES		使用基于接口的代理(jdk dynamic proxy)。
	* 	TARGET_CLASS	使用基于類的代理(cglib)。
    */
	ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}

通過代碼我們可以清晰的看到兩個主要屬性value 和 proxyMode,value就不多說了,大家平時經(jīng)常用看看注解就可以。proxyMode 這個就有意思了,而這個就是@RefreshScope 實(shí)現(xiàn)的本質(zhì)了。

我們需要關(guān)心的就是ScopedProxyMode.TARGET_CLASS 這個屬性,當(dāng)ScopedProxyMode 為TARGET_CLASS 的時候會給當(dāng)前創(chuàng)建的bean 生成一個代理對象,會通過代理對象來訪問,每次訪問都會創(chuàng)建一個新的對象。

理解起來可能比較晦澀,那先來看下實(shí)現(xiàn)再回頭來看這句話。

三、RefreshScope 的實(shí)現(xiàn)原理

先來看下@RefreshScope

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {
	/**
	 * @see Scope#proxyMode()
	 */
	ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}

2. 可以看出,它使用就是 @Scope ,其內(nèi)部就一個屬性默認(rèn) ScopedProxyMode.TARGET_CLASS。知道了是通過Spring Scope 來實(shí)現(xiàn)的那就簡單了,我們來看下Scope 這個接口

public interface Scope {
	/**
	 * Return the object with the given name from the underlying scope,
	 * {@link org.springframework.beans.factory.ObjectFactory#getObject() creating it}
	 * if not found in the underlying storage mechanism.
	 * <p>This is the central operation of a Scope, and the only operation
	 * that is absolutely required.
	 * @param name the name of the object to retrieve
	 * @param objectFactory the {@link ObjectFactory} to use to create the scoped
	 * object if it is not present in the underlying storage mechanism
	 * @return the desired object (never {@code null})
	 * @throws IllegalStateException if the underlying scope is not currently active
	 */
	Object get(String name, ObjectFactory<?> objectFactory);
	@Nullable
	Object remove(String name);
	void registerDestructionCallback(String name, Runnable callback);
	@Nullable
	Object resolveContextualObject(String key);
	@Nullable
	String getConversationId();
}

看下接口,我們只看Object get(String name, ObjectFactory<?> objectFactory); 這個方法幫助我們來創(chuàng)建一個新的bean ,也就是說,@RefreshScope 在調(diào)用 刷新的時候會使用此方法來給我們創(chuàng)建新的對象,這樣就可以通過spring 的裝配機(jī)制將屬性重新注入了,也就實(shí)現(xiàn)了所謂的動態(tài)刷新。

那它究竟是怎么處理老的對象,又怎么除法創(chuàng)建新的對象呢?

在開頭我提過幾個重要的類,而其中 RefreshScope extends GenericScope, GenericScope implements Scope。

所以通過查看代碼,是GenericScope 實(shí)現(xiàn)了 Scope 最重要的 get(String name, ObjectFactory<?> objectFactory) 方法,在GenericScope 里面 包裝了一個內(nèi)部類 BeanLifecycleWrapperCache 來對加了 @RefreshScope 從而創(chuàng)建的對象進(jìn)行緩存,使其在不刷新時獲取的都是同一個對象。(這里你可以把 BeanLifecycleWrapperCache 想象成為一個大Map 緩存了所有@RefreshScope 標(biāo)注的對象)

知道了對象是緩存的,所以在進(jìn)行動態(tài)刷新的時候,只需要清除緩存,重新創(chuàng)建就好了。

來看代碼,眼見為實(shí),只留下關(guān)鍵方法:

// ContextRefresher 外面使用它來進(jìn)行方法調(diào)用 ============================== 我是分割線
	public synchronized Set<String> refresh() {
		Set<String> keys = refreshEnvironment();
		this.scope.refreshAll();
		return keys;
	}
// RefreshScope 內(nèi)部代碼  ============================== 我是分割線
	@ManagedOperation(description = "Dispose of the current instance of all beans in this scope and force a refresh on next method execution.")
	public void refreshAll() {
		super.destroy();
		this.context.publishEvent(new RefreshScopeRefreshedEvent());
	}
// GenericScope 里的方法 ============================== 我是分割線
	//進(jìn)行對象獲取,如果沒有就創(chuàng)建并放入緩存
	@Override
	public Object get(String name, ObjectFactory<?> objectFactory) {
		BeanLifecycleWrapper value = this.cache.put(name,
				new BeanLifecycleWrapper(name, objectFactory));
		locks.putIfAbsent(name, new ReentrantReadWriteLock());
		try {
			return value.getBean();
		}
		catch (RuntimeException e) {
			this.errors.put(name, e);
			throw e;
		}
	}
	//進(jìn)行緩存的數(shù)據(jù)清理
	@Override
	public void destroy() {
		List<Throwable> errors = new ArrayList<Throwable>();
		Collection<BeanLifecycleWrapper> wrappers = this.cache.clear();
		for (BeanLifecycleWrapper wrapper : wrappers) {
			try {
				Lock lock = locks.get(wrapper.getName()).writeLock();
				lock.lock();
				try {
					wrapper.destroy();
				}
				finally {
					lock.unlock();
				}
			}
			catch (RuntimeException e) {
				errors.add(e);
			}
		}
		if (!errors.isEmpty()) {
			throw wrapIfNecessary(errors.get(0));
		}
		this.errors.clear();
	}

通過觀看源代碼我們得知,我們截取了三個片段所得之,ContextRefresher 就是外層調(diào)用方法用的,GenericScope 里面的 get 方法負(fù)責(zé)對象的創(chuàng)建和緩存,destroy 方法負(fù)責(zé)再刷新時緩存的清理工作。當(dāng)然spring n內(nèi)部還進(jìn)行很多其他有趣的處理,有興趣的同學(xué)可以詳細(xì)看一下。

四、總結(jié)

綜上所述,來總結(jié)下@RefreshScope 實(shí)現(xiàn)流程

  • 需要動態(tài)刷新的類標(biāo)注@RefreshScope 注解
  • @RefreshScope 注解標(biāo)注了@Scope 注解,并默認(rèn)了ScopedProxyMode.TARGET_CLASS; 屬性,此屬性的功能就是在創(chuàng)建一個代理,在每次調(diào)用的時候都用它來調(diào)用GenericScope get 方法來獲取對象
  • 如屬性發(fā)生變更會調(diào)用 ContextRefresher refresh() -》RefreshScope refreshAll() 進(jìn)行緩存清理方法調(diào)用,并發(fā)送刷新事件通知 -》 GenericScope 真正的 清理方法destroy() 實(shí)現(xiàn)清理緩存
  • 在下一次使用對象的時候,會調(diào)用GenericScope get(String name, ObjectFactory<?> objectFactory) 方法創(chuàng)建一個新的對象,并存入緩存中,此時新對象因?yàn)镾pring 的裝配機(jī)制就是新的屬性了。

以上就是SpringCloud @RefreshScope刷新機(jī)制淺析的詳細(xì)內(nèi)容,更多關(guān)于SpringCloud @RefreshScope的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于SpringBoot解決CORS跨域的問題(@CrossOrigin)

    基于SpringBoot解決CORS跨域的問題(@CrossOrigin)

    這篇文章主要介紹了基于SpringBoot解決CORS跨域的問題(@CrossOrigin),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • java返回的List進(jìn)行add操作報錯

    java返回的List進(jìn)行add操作報錯

    本文主要介紹了java返回的List進(jìn)行add操作報錯,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • 5分鐘快速了解String.trim()到底做了什么事

    5分鐘快速了解String.trim()到底做了什么事

    trim方法一般用來去除空格,但是根據(jù)JDK API的說明,該方法并不僅僅是去除空格,它能夠去除從編碼'\u0000'至'\u0020'的所有字符,這篇文章主要給大家介紹了如何通過5分鐘快速了解String.trim()到底做了什么事,需要的朋友可以參考下
    2021-11-11
  • 幾種常見mybatis分頁的實(shí)現(xiàn)方式

    幾種常見mybatis分頁的實(shí)現(xiàn)方式

    這篇文章主要介紹了幾種常見mybatis分頁的實(shí)現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Lombok同時使?@Data和@Builder踩坑總結(jié)

    Lombok同時使?@Data和@Builder踩坑總結(jié)

    這篇文章主要介紹了Lombok同時使?@Data和@Builder踩坑總結(jié),文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值需要的小伙伴可以參考一下,希望對你的學(xué)習(xí)有所幫助
    2022-05-05
  • @Transactional注解異常報錯之多數(shù)據(jù)源詳解

    @Transactional注解異常報錯之多數(shù)據(jù)源詳解

    這篇文章主要介紹了@Transactional注解異常報錯之多數(shù)據(jù)源詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • idea 解決用骨架創(chuàng)建項(xiàng)目過慢的操作方式

    idea 解決用骨架創(chuàng)建項(xiàng)目過慢的操作方式

    這篇文章主要介紹了idea 解決用骨架創(chuàng)建項(xiàng)目過慢的操作方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • 將SpringBoot項(xiàng)目無縫部署到Tomcat服務(wù)器的操作流程

    將SpringBoot項(xiàng)目無縫部署到Tomcat服務(wù)器的操作流程

    SpringBoot 是一個用來簡化 Spring 應(yīng)用初始搭建以及開發(fā)過程的框架,我們可以通過內(nèi)置的 Tomcat 容器來輕松地運(yùn)行我們的應(yīng)用,本文給大家介紹 SpringBoot 項(xiàng)目部署到獨(dú)立 Tomcat 服務(wù)器的操作流程,需要的朋友可以參考下
    2024-05-05
  • Java用鄰接矩陣存儲圖的示例代碼

    Java用鄰接矩陣存儲圖的示例代碼

    鄰接矩陣通常采用一個一維數(shù)組存儲圖中節(jié)點(diǎn)的信息,采用一個二維數(shù)組存儲圖中節(jié)點(diǎn)之間的鄰接關(guān)系。本文將利用Java實(shí)現(xiàn)用鄰接矩陣存儲圖,需要的可以參考一下
    2022-06-06
  • 探討Java驗(yàn)證碼制作(下篇)

    探討Java驗(yàn)證碼制作(下篇)

    這篇文章主要介紹了探討Java驗(yàn)證碼制作(下篇)的相關(guān)資料,需要的朋友可以參考下
    2016-05-05

最新評論

六盘水市| 辽源市| 岳阳市| 阿合奇县| 邹城市| 巩义市| 页游| 义乌市| 麻栗坡县| 东乌珠穆沁旗| 略阳县| 巴中市| 嘉义市| 江口县| 黄骅市| 会理县| 建德市| 全南县| 扶沟县| 呼图壁县| 安乡县| 宣汉县| 林芝县| 渑池县| 林州市| 宜春市| 齐齐哈尔市| 启东市| 卢龙县| 且末县| 三江| 延吉市| 绥滨县| 阿巴嘎旗| 朔州市| 都匀市| 上饶市| 延边| 兴义市| 太湖县| 阿克陶县|