Spring Boot小型項目如何使用異步任務管理器實現不同業務間的解耦

前言

在有些業務場景中,系統對於響應時間有一定的要求,而一個方法裡面同步執行的業務邏輯太多勢必會影響響應速度,帶來不好的用戶體驗。比如登錄時記錄登錄用戶的訪問記錄、註冊時發送郵件、短信通知等等場景,不需要等待處理結果之後再進行下一步操作,這時候就可以使用異步線程進行處理,這樣主線程不會因為這些耗時的操作而阻塞,保證主線程的流程可以正常進行。

異步任務可以通過多線程也可以通過消息隊列來實現,目的都是為瞭實現不同業務之間的解耦,提高業務系統的響應速度。但是相對於小型系統采用多線程的方式相對更便捷,所以,這篇文章就記錄一下我是如何使用多線程實現異步任務管理器來記錄訪問日志的。

一、異步任務管理器是什麼?

顧名思義,就是用來對異步任務進行統一的管理,並提供瞭一種訪問其唯一對象的方式,這樣做的好處就是,在內存中有且僅有一個實例,減少瞭內存的開銷,尤其對於頻繁的創建和銷毀實例,用這種方式來頻繁執行多個異步任務性能是相對比較好的。

二、實現步驟

1.自定義線程池

執行異步任務時,需要將執行的任務放入到線程池中,所以需配置好我們的線程池。並創建一個調度線程池執行器,用來執行異步任務。

代碼如下(示例):

2. 新建異步任務管理器類

代碼如下(示例):

public class AsyncManager {
    /**
     * 操作延遲10毫秒
     */
    private final int OPERATE_DELAY_TIME = 10;
    /**
     * 異步操作任務調度線程池
     */
    private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
    /**
     * 餓漢式單例模式
     */
    private AsyncManager(){}

    private static AsyncManager me = new AsyncManager();

    public static AsyncManager me() {
        return me;
    }
    /**
     * 執行任務
     * @param task 任務
     */
    public void execute(TimerTask task) {
        executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
    }

3. 新建異步工廠類

設計這個類主要是用來產生 TimerTask 的,代碼如下(示例):

@Slf4j
public class AsyncFactory {
    /**
     * 記錄登錄信息
     * @param username 用戶名
     * @param status 狀態
     * @param message 消息
     * @param args 列表
     * @return 任務task
     */
    public static TimerTask recordLoginLog(final String username, final String status, final String message,final Object... args) {
        // 客戶端操作系統、瀏覽器等信息
        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);
                // 獲取客戶端操作系統
                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());
                // 日志狀態
                if (Constants.LOGIN_FAIL.equals(status)) {
                    loginLog.setStatus(Integer.valueOf(Constants.FAIL));
                } else {
                    loginLog.setStatus(Integer.valueOf(Constants.SUCCESS));
                }
                // 插入數據
                SpringUtils.getBean(IXlLoginLogService.class).create(loginLog);
            }
        };
    }
}

4. 調用

例如:在登錄的方法中鏈式調用,與同步方式不同,開發者不用考慮當進行登錄操作是否進行日志操作,在異步的方式中,業務的操作與日志的操作分開來。執行流程:AsyncManager.me()獲取一個AsyncManager對象,執行execute方法,執行任務,傳入的是一個task對象。實現瞭Runnable接口,是一個任務,由線程Thread去執行。

recordLoginLog方法返回的是TimerTask定時任務類,將用戶登錄信息記錄到日志中作為一個定時任務,交給定時任務調度線程池scheduledExecutorService,scheduledExecutorService通過在異步任務管理器類中,用getBean()從IOC容器中獲取。

5. 實現效果

進行登錄操作時,會異步進行日志的記錄。

總結

到此這篇關於Spring Boot小型項目如何使用異步任務管理器實現不同業務間的解耦的文章就介紹到這瞭,更多相關Spring Boot實現不同業務間解耦內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: