AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當前位置:首頁 > 科技  > 軟件

我跟你說@RefreshScope跟Spring事件監聽一起用有坑!

來源: 責編: 時間:2024-07-09 06:59:41 741觀看
導讀本文記錄一下我在 Spring 自帶的事件監聽類添加 @RefreshScope 注解時遇到的坑,原本這兩個東西單獨使用是各自安好,但當大家將它們組合在一起時,會發現我們的事件監聽代碼被重復執行。希望大家引以為鑒,避免重復踩坑。耐

本文記錄一下我在 Spring 自帶的事件監聽類添加 @RefreshScope 注解時遇到的坑,原本這兩個東西單獨使用是各自安好,但當大家將它們組合在一起時,會發現我們的事件監聽代碼被重復執行。希望大家引以為鑒,避免重復踩坑。耐心看完,你一定會有所收獲!1fq28資訊網——每日最新資訊28at.com

前置描述

最近有一個用戶拉新的需求,需要在新用戶注冊時判斷用戶是否有對應的邀請關系,如果有則需要給新用戶贈送系統資源。1fq28資訊網——每日最新資訊28at.com

原有的用戶注冊邏輯里使用了 Spring 自帶的事件監聽工具,也就是 applicationEventPublisher(事件發布類)以及 ApplicationListener(事件監聽類),在用戶注冊完畢寫入用戶記錄并生成 token 后,會觸發 RegisterEvent(注冊事件)的發布。偽代碼如下,1fq28資訊網——每日最新資訊28at.com

// 1. 用戶注冊,寫入數據庫RegisterResponseVO registerResponseVO = memberRegisterService.register(new RegisterRequestVO(request);// 2. 生成tokenString token = getToken(memberEntity.getId(), request.getSource());log.info("login mobile {} login token {}", request.getMobile(), token);// 3. 發布注冊事件,會觸發登錄日志監聽、優惠券贈送監聽等applicationEventPublisher.publishEvent(new RegisterEvent(request, memberEntity, token));

由于之前代碼已經使用事件監聽邏輯,所以這里我們的新用戶注冊判斷邀請關系的邏輯就直接新建一個 NewUserInvitedListener 監聽類即可。偽代碼如下,1fq28資訊網——每日最新資訊28at.com

@Slf4j@RefreshScope@AllArgsConstructor@Componentpublic class NewUserInvitedListener implements ApplicationListener<RegisterEvent> {    @Async("asyncServiceExecutor")    @Override    public void onApplicationEvent(RegisterEvent registerEvent) {        UserLoginRequestVO requestVO = registerEvent.getRequestVO();        MemberEntity memberEntity = registerEvent.getMemberEntity();        log.info("================ NewUserInvitedListener =============== registerEvent is {}", registerEvent);        // 1. 校驗邏輯        validateUser(memberEntity);        // 2. 判斷用戶是否有邀請關系        // 3. 如果有則贈送系統資源        ...    }}

OK,代碼邏輯也不復雜,寫完提測交給測試下班(周五下午寫完)。1fq28資訊網——每日最新資訊28at.com

發現問題

周一一來,測試就在群里 @ 后端人員說是新用戶贈送的系統資源送了兩次,說實話我一開始是不太信的,直到我去查了日志,發現 NewUserInvitedListener 監聽類的日志確實被打印了兩次,也就是說我們的 NewUserInvitedListener 監聽類被觸發了兩次。1fq28資訊網——每日最新資訊28at.com

OK,到這里我們的問題就確確實實產生了,接下來就是解決問題。1fq28資訊網——每日最新資訊28at.com

解決思路

問題產生通常都有很多種解決方法,我們如何選擇一個最適合我們當前場景的方法才能體現出我們對業務、技術的理解。在這個監聽類重復觸發的場景里,就有多種解決方式,我簡單列舉幾個,1fq28資訊網——每日最新資訊28at.com

  1. 添加冪等處理,防止重復執行
  2. 加鎖,防止重復執行
  3. 解決下為什么監聽類會重復觸發

這三個解決方案各有優劣,通過對監聽類的業務邏輯添加冪等邏輯或者加鎖邏輯都是可以解決的,但是這不是問題根源,問題根源是在于監聽類為什么會被重復觸發。在本文中,我也將帶著大家一步一步探索并解決這個問題。1fq28資訊網——每日最新資訊28at.com

檢查下之前的事件監聽類是否也有重復觸發的問題

因為這個代碼是照著之前的邏輯寫的,新加的 NewUserInvitedListener 被發現重復觸發,那以前的 MemberLoginLogListener 是否也有重復觸發的問題。偽代碼如下,1fq28資訊網——每日最新資訊28at.com

@Slf4j@Component@AllArgsConstructorpublic class MemberLoginLogListener implements ApplicationListener<RegisterEvent> {    private MemberLoginLogService memberLoginLogService;    @Async("asyncServiceExecutor")    @Override    public void onApplicationEvent(RegisterEvent event) {        MemberEntity memberEntity = event.getMemberEntity();        log.info("================ MemberLoginLogListener ===============, mobile is {}", memberEntity.getMobile());        MemberLoginLogEntity memberLoginLogEntity = MemberLoginLogConvertor.buildLoginLogEntity(event.getRequestVO(),                event.getMemberEntity());        memberLoginLogEntity.setToken(event.getToken());        memberLoginLogService.save(memberLoginLogEntity);    }}

查詢 MemberLoginLogListener 監聽類的日志,發現只有一次打印,說明之前寫的 MemberLoginLogListener 監聽類沒有重復觸發的問題,那這里就很奇怪了。對比一下 NewUserInvitedListener 監聽類與 MemberLoginLogListener 監聽類的差別,很明顯我們發現 NewUserInvitedListener 監聽類上多了一個 @RefreshScope 注解。1fq28資訊網——每日最新資訊28at.com

OK,問題有可能就是 @RefreshScope 注解導致,我們去掉 @RefreshScope 注解在看看日志打印。1fq28資訊網——每日最新資訊28at.com

去掉 @RefreshScope 注解

當我們去掉 @RefreshScope 注解后,神奇的事情發生了,NewUserInvitedListener 監聽類的日志打印正常了,只觸發了一次!OK,到這里我們也就發現了問題出在 @RefreshScope 注解上。1fq28資訊網——每日最新資訊28at.com

如何搜索問題

雖然我們知道了問題出在 @RefreshScope 注解上,但是我們怎么向搜索引擎描述這個問題嘞?1fq28資訊網——每日最新資訊28at.com

很多人發現了問題,但是不知道如何描述問題,怎么描述問題才能讓別人一聽就懂,從而能給你提供幫助。你需要把問題的重點描述出來,搜索引擎才能給予精準幫助。1fq28資訊網——每日最新資訊28at.com

在我們這個新用戶注冊判斷邀請關系的場景里,很顯然我們的搜索詞可以是 “spring 事件監聽重復觸發 @RefreshScope”可以看到我的搜索關鍵詞有 3 個,分別是 spring、事件監聽重復觸發以及 @RefreshScope。讓我們來看看搜索結果。1fq28資訊網——每日最新資訊28at.com

圖片圖片1fq28資訊網——每日最新資訊28at.com

前 5 個搜索結果中,只有第五個的標題可能符合我們的搜索內容,我們點進去看一看。1fq28資訊網——每日最新資訊28at.com

圖片圖片1fq28資訊網——每日最新資訊28at.com

很遺憾,跟我們的問題場景并不相符,我們并沒有搜索到我們想要的東西。在這里我們的搜索關鍵詞“spring 事件監聽重復觸發 @RefreshScope”并沒有給予我們幫助。1fq28資訊網——每日最新資訊28at.com

回到問題本身

既然我們的問題已經定位到了,在于 @RefreshScope 會導致監聽類的重復觸發,可是這個關鍵詞并沒有相關搜索結果,那么我們只能換個角度。1fq28資訊網——每日最新資訊28at.com

為什么會重復觸發?1fq28資訊網——每日最新資訊28at.com

在 NewUserInvitedListener 監聽類中,我們使用 @Component 注解,默認注冊了一個單例 bean,這個 bean 用于接收用戶注冊事件。既然 bean 是單一的,那就是說 Spring 發送了 2 次 RegisterEvent 事件嗎?結合上文提到的 MemberLoginLogListener 監聽類只觸發一次的日志,很顯然,Spring 只會發送了 1 次 RegisterEvent 事件。1fq28資訊網——每日最新資訊28at.com

難道說問題在于 Spring 里出現了兩個 NewUserInvitedListener 類型的 bean?1fq28資訊網——每日最新資訊28at.com

那么到這里恭喜我們終于定位到了重復觸發問題的根源。1fq28資訊網——每日最新資訊28at.com

如果大家了解 @RefreshScope 的原理相信大家已經猜出來了。1fq28資訊網——每日最新資訊28at.com

@RefreshScope 原理

Spring 中 @scope 注解的原理就是在創建 Scope=singleton 的 Bean 時,IOC 會保存實例在一個 Map 中,保證這個 Bean 在一個 IOC 上下文有且僅有一個實例。1fq28資訊網——每日最新資訊28at.com

SpringCloud 新增了一個自定義的作用域:refresh(可以理解為“動態刷新”),同樣用了一種獨特的方式改變了 Bean 的管理方式,使得其可以通過外部化配置(.properties)的刷新,在應用不需要重啟的情況下熱加載新的外部化配置的值。1fq28資訊網——每日最新資訊28at.com

這個 scope 是如何做到熱加載的呢?RefreshScope 主要做了以下動作:單獨管理 Bean 生命周期1fq28資訊網——每日最新資訊28at.com

創建 Bean 的時候如果是 RefreshScope 就緩存在一個專門管理的 ScopeMap 中,這樣就可以管理 Scope 是 Refresh 的 Bean 的生命周期了(所以含 RefreshScope 的其實一共創建了兩個 bean)。1fq28資訊網——每日最新資訊28at.com

重新創建 Bean1fq28資訊網——每日最新資訊28at.com

外部化配置刷新之后,會觸發一個動作,這個動作將上面的 ScopeMap 中的 Bean 清空,這樣這些 Bean 就會重新被 IOC 容器創建一次,使用最新的外部化配置的值注入類中,達到熱加載新值的效果。1fq28資訊網——每日最新資訊28at.com

看完 @RefreshScope 的原理相信大家已經知道了出現兩個 NewUserInvitedListener 類型 bean 的原因是在于 @RefreshScope 導致。這是由于 @RefreshScope 注解的內部實現創建了另外一個相同類型的 NewUserInvitedListener bean,導致我們的新用戶監聽邏輯被重復執行。1fq28資訊網——每日最新資訊28at.com

回到搜索關鍵詞

假如我是說假如,假如我們不知道 @RefreshScope 的原理,自然不知道項目中出現了兩個 NewUserInvitedListener 類型的 bean 是 @RefreshScope 導致。那么我們怎么通過搜索關鍵詞來找到這個問題嘞?1fq28資訊網——每日最新資訊28at.com

到這里也就是本文的重點所在,怎么通過搜索關鍵詞來解決我們的問題。1fq28資訊網——每日最新資訊28at.com

先定義問題

在這個場景里我們使用的是 Spring 項目,問題本質是 @RefreshScope 在 Spring 自帶的事件監聽類搭配使用時,由于 @RefreshScope 會導致 bean 重復進而導致重復觸發。1fq28資訊網——每日最新資訊28at.com

總結關鍵詞

在上面的先定義問題中,我們提煉一下關鍵詞,1fq28資訊網——每日最新資訊28at.com

  • Spring:這個關鍵詞在 Spring 項目中必帶,大家應該沒有意見把
  • @RefreshScope:我們的問題根源,搜索也得帶上
  • 生成同一個 bean:這是一個描述語句,簡要描述一下我們發現的問題

看一看搜索結果,1fq28資訊網——每日最新資訊28at.com

圖片圖片1fq28資訊網——每日最新資訊28at.com

點進第一個結果,1fq28資訊網——每日最新資訊28at.com

圖片圖片1fq28資訊網——每日最新資訊28at.com

OK,大功告成,看到我們框選中的地方了嗎,上文的 @RefreshScope 原理解釋,就是復制與這里。1fq28資訊網——每日最新資訊28at.com

貼一下原文地址:https://blog.csdn.net/m0_71777195/article/details/1272235441fq28資訊網——每日最新資訊28at.com

一些思考

實話實說,我在測試給我上報問題,到發現這個問題來自于 @RefreshScope 注解只用了 10 分鐘,如上文所說,我通過對比以前寫的 MemberLoginLogListener 監聽類,早早的定位到問題來自于 @RefreshScope 注解??墒堑轿彝暾迯瓦@個問題,提交到測試環境,卻花了 2 個半小時,原因是因為我在研究這個問題的根源,這也是這篇文章的由來。1fq28資訊網——每日最新資訊28at.com

假如說這個問題發生在線上,那么我根本不可能花這么多時間來研究,我需要的就是迅速解決這個問題并修復上線,避免影響更多用戶。1fq28資訊網——每日最新資訊28at.com

一樣的,大家在遇到這種相似問題時,如果境況緊急出現在生產環境,大家本著對工作負責的態度,應該迅速解決并做故障復盤。如果是出現在測試環境我們可以本著對技術執著可以認真專研下這個問題。1fq28資訊網——每日最新資訊28at.com

其實我還想說的是在這個問題里,我能 10 分鐘定位到問題來自于 @RefreshScope 注解,可能也有運氣成分。但是很多情況下當我們照驢子畫馬寫代碼,發現出了問題時,這種情況大部分還是我們“畫蛇添足”導致。大家可以通過對比以前代碼迅速找出問題原因。1fq28資訊網——每日最新資訊28at.com

找出了問題后是如何解決問題。這篇文章里,我給大家講了講我的搜索關鍵詞心得。第一是講重點、第二是找到問題本質,這樣才能從搜索引擎嘴里找出我們想要的答案。1fq28資訊網——每日最新資訊28at.com

本文鏈接:http://www.tebozhan.com/showinfo-26-99639-0.html我跟你說@RefreshScope跟Spring事件監聽一起用有坑!

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 有使用過vm.$set嗎,原理是什么?

下一篇: 2024 Vue 生態工具最能打的組合!

標簽:
  • 熱門焦點
Top