<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
用過Spring Cloud的同學都知道在使用動態設定重新整理的我們要設定一個@RefreshScope 在類上才可以實現物件屬性的的動態更新,本著知其所以然的態度,晚上沒事兒又把這個點回顧了一下,下面就來簡單的說下自己的理解。
總覽下,實現@RefreshScope 動態重新整理的就需要以下幾個:
一句話,@RefreshScope 能實現動態重新整理全仰仗著@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是單例的。(預設) * prototype 表示該bean是多例的,即每次使用該bean時都會新建一個物件。 * request 在一次http請求中,一個bean對應一個範例。 * session 在一個httpSession中,一個bean對應一個範例 */ @AliasFor("value") String scopeName() default ""; /** * DEFAULT 不使用代理。(預設) * NO 不使用代理,等價於DEFAULT。 * INTERFACES 使用基於介面的代理(jdk dynamic proxy)。 * TARGET_CLASS 使用基於類的代理(cglib)。 */ ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT; }
通過程式碼我們可以清晰的看到兩個主要屬性value 和 proxyMode,value就不多說了,大家平時經常用看看註解就可以。proxyMode 這個就有意思了,而這個就是@RefreshScope 實現的本質了。
我們需要關心的就是ScopedProxyMode.TARGET_CLASS 這個屬性,當ScopedProxyMode 為TARGET_CLASS 的時候會給當前建立的bean 生成一個代理物件,會通過代理物件來存取,每次存取都會建立一個新的物件。
理解起來可能比較晦澀,那先來看下實現再回頭來看這句話。
先來看下@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 ,其內部就一個屬性預設 ScopedProxyMode.TARGET_CLASS。知道了是通過Spring Scope 來實現的那就簡單了,我們來看下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); 這個方法幫助我們來建立一個新的bean ,也就是說,@RefreshScope 在呼叫 重新整理的時候會使用此方法來給我們建立新的物件,這樣就可以通過spring 的裝配機制將屬性重新注入了,也就實現了所謂的動態重新整理。
那它究竟是怎麼處理老的物件,又怎麼除法建立新的物件呢?
在開頭我提過幾個重要的類,而其中 RefreshScope extends GenericScope, GenericScope implements Scope。
所以通過檢視程式碼,是GenericScope 實現了 Scope 最重要的 get(String name, ObjectFactory<?> objectFactory) 方法,在GenericScope 裡面 包裝了一個內部類 BeanLifecycleWrapperCache 來對加了 @RefreshScope 從而建立的物件進行快取,使其在不重新整理時獲取的都是同一個物件。(這裡你可以把 BeanLifecycleWrapperCache 想象成為一個大Map 快取了所有@RefreshScope 標註的物件)
知道了物件是快取的,所以在進行動態重新整理的時候,只需要清除快取,重新建立就好了。
來看程式碼,眼見為實,只留下關鍵方法:
// ContextRefresher 外面使用它來進行方法呼叫 ============================== 我是分割線 public synchronized Set<String> refresh() { Set<String> keys = refreshEnvironment(); this.scope.refreshAll(); return keys; } // RefreshScope 內部程式碼 ============================== 我是分割線 @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 裡的方法 ============================== 我是分割線 //進行物件獲取,如果沒有就建立並放入快取 @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; } } //進行快取的資料清理 @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 就是外層呼叫方法用的,GenericScope 裡面的 get 方法負責物件的建立和快取,destroy 方法負責再重新整理時快取的清理工作。當然spring n內部還進行很多其他有趣的處理,有興趣的同學可以詳細看一下。
綜上所述,來總結下@RefreshScope 實現流程
以上就是SpringCloud @RefreshScope重新整理機制淺析的詳細內容,更多關於SpringCloud @RefreshScope的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45