Spring?Boot小型項目如何使用異步任務(wù)管理器實現(xiàn)不同業(yè)務(wù)間的解耦
前言
在有些業(yè)務(wù)場景中,系統(tǒng)對于響應(yīng)時間有一定的要求,而一個方法里面同步執(zhí)行的業(yè)務(wù)邏輯太多勢必會影響響應(yīng)速度,帶來不好的用戶體驗。比如登錄時記錄登錄用戶的訪問記錄、注冊時發(fā)送郵件、短信通知等等場景,不需要等待處理結(jié)果之后再進行下一步操作,這時候就可以使用異步線程進行處理,這樣主線程不會因為這些耗時的操作而阻塞,保證主線程的流程可以正常進行。
異步任務(wù)可以通過多線程也可以通過消息隊列來實現(xiàn),目的都是為了實現(xiàn)不同業(yè)務(wù)之間的解耦,提高業(yè)務(wù)系統(tǒng)的響應(yīng)速度。但是相對于小型系統(tǒng)采用多線程的方式相對更便捷,所以,這篇文章就記錄一下我是如何使用多線程實現(xiàn)異步任務(wù)管理器來記錄訪問日志的。
一、異步任務(wù)管理器是什么?
顧名思義,就是用來對異步任務(wù)進行統(tǒng)一的管理,并提供了一種訪問其唯一對象的方式,這樣做的好處就是,在內(nèi)存中有且僅有一個實例,減少了內(nèi)存的開銷,尤其對于頻繁的創(chuàng)建和銷毀實例,用這種方式來頻繁執(zhí)行多個異步任務(wù)性能是相對比較好的。
二、實現(xiàn)步驟
1.自定義線程池
執(zhí)行異步任務(wù)時,需要將執(zhí)行的任務(wù)放入到線程池中,所以需配置好我們的線程池。并創(chuàng)建一個調(diào)度線程池執(zhí)行器,用來執(zhí)行異步任務(wù)。
代碼如下(示例):
2. 新建異步任務(wù)管理器類
代碼如下(示例):
public class AsyncManager { /** * 操作延遲10毫秒 */ private final int OPERATE_DELAY_TIME = 10; /** * 異步操作任務(wù)調(diào)度線程池 */ private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService"); /** * 餓漢式單例模式 */ private AsyncManager(){} private static AsyncManager me = new AsyncManager(); public static AsyncManager me() { return me; } /** * 執(zhí)行任務(wù) * @param task 任務(wù) */ public void execute(TimerTask task) { executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS); }
3. 新建異步工廠類
設(shè)計這個類主要是用來產(chǎn)生 TimerTask 的,代碼如下(示例):
@Slf4j public class AsyncFactory { /** * 記錄登錄信息 * @param username 用戶名 * @param status 狀態(tài) * @param message 消息 * @param args 列表 * @return 任務(wù)task */ public static TimerTask recordLoginLog(final String username, final String status, final String message,final Object... args) { // 客戶端操作系統(tǒng)、瀏覽器等信息 final UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent")); // 請求的IP地址 final String ip = ServletUtil.getClientIP(ServletUtils.getRequest()); return new TimerTask() { @Override public void run() { String address = AddressUtils.getRealAddressByIp(ip); // 獲取客戶端操作系統(tǒng) String os = userAgent.getOs().getName(); // 獲取客戶端瀏覽器 String browser = userAgent.getBrowser().getName(); // 封裝對象 XlLoginLog loginLog = new XlLoginLog(); loginLog.setUserCode(username); loginLog.setIpaddr(ip); loginLog.setLoginLocation(address); loginLog.setBrowser(browser); loginLog.setOs(os); loginLog.setMsg(message); loginLog.setLoginTime(new Date()); // 日志狀態(tài) if (Constants.LOGIN_FAIL.equals(status)) { loginLog.setStatus(Integer.valueOf(Constants.FAIL)); } else { loginLog.setStatus(Integer.valueOf(Constants.SUCCESS)); } // 插入數(shù)據(jù) SpringUtils.getBean(IXlLoginLogService.class).create(loginLog); } }; } }
4. 調(diào)用
例如:在登錄的方法中鏈式調(diào)用,與同步方式不同,開發(fā)者不用考慮當進行登錄操作是否進行日志操作,在異步的方式中,業(yè)務(wù)的操作與日志的操作分開來。執(zhí)行流程:AsyncManager.me()獲取一個AsyncManager對象,執(zhí)行execute方法,執(zhí)行任務(wù),傳入的是一個task對象。實現(xiàn)了Runnable接口,是一個任務(wù),由線程Thread去執(zhí)行。
recordLoginLog方法返回的是TimerTask定時任務(wù)類,將用戶登錄信息記錄到日志中作為一個定時任務(wù),交給定時任務(wù)調(diào)度線程池scheduledExecutorService,scheduledExecutorService通過在異步任務(wù)管理器類中,用getBean()從IOC容器中獲取。
5. 實現(xiàn)效果
進行登錄操作時,會異步進行日志的記錄。
總結(jié)
到此這篇關(guān)于Spring Boot小型項目如何使用異步任務(wù)管理器實現(xiàn)不同業(yè)務(wù)間的解耦的文章就介紹到這了,更多相關(guān)Spring Boot實現(xiàn)不同業(yè)務(wù)間解耦內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何解決Gradle、Maven項目build后沒有mybatis的mapper.xml文件的問題
這篇文章主要介紹了如何解決Gradle、Maven項目build后沒有mybatis的mapper.xml文件的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01Mybatis-plus通過添加攔截器實現(xiàn)簡單數(shù)據(jù)權(quán)限
系統(tǒng)需要根據(jù)用戶所屬的公司,來做一下數(shù)據(jù)權(quán)限控制,具體一點,就是通過表中的company_id進行權(quán)限控制,項目使用的是mybatis-plus,所以通過添加攔截器的方式,修改查詢sql,實現(xiàn)數(shù)據(jù)權(quán)限,本文就通過代碼給大家詳細的講解一下,需要的朋友可以參考下2023-08-08Spring和SpringMVC父子容器關(guān)系初窺(小結(jié))
這篇文章主要介紹了Spring和SpringMVC父子容器關(guān)系初窺(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01基于Java創(chuàng)建XML(無中文亂碼)過程解析
這篇文章主要介紹了基于Java創(chuàng)建XML(無中文亂碼)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-10-10SSM框架下如何實現(xiàn)數(shù)據(jù)從后臺傳輸?shù)角芭_
這篇文章主要介紹了SSM框架下如何實現(xiàn)數(shù)據(jù)從后臺傳輸?shù)角芭_,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05