摘要:動態(tài)腳本支持框架之結(jié)構(gòu)設(shè)計篇相關(guān)博文動態(tài)腳本支持框架整體介紹篇動態(tài)腳本支持框架之使用介紹篇前面兩篇博文,主要是整體介紹和如何使用接下來開始進入正題,逐步剖析,這個項目是怎么一步一步搭建起來的本篇博文則主要介紹基本骨架的設(shè)計,圍繞項目
Quick-Task 動態(tài)腳本支持框架之結(jié)構(gòu)設(shè)計篇
相關(guān)博文:
180702-QuickTask動態(tài)腳本支持框架整體介紹篇
180719-Quick-Task 動態(tài)腳本支持框架之使用介紹篇
前面兩篇博文,主要是整體介紹和如何使用;接下來開始進入正題,逐步剖析,這個項目是怎么一步一步搭建起來的;本篇博文則主要介紹基本骨架的設(shè)計,圍繞項目的核心點,實現(xiàn)一個基礎(chǔ)的原型系統(tǒng)
I. 結(jié)構(gòu)分析整體設(shè)計圖如下:
對于上面的圖,得有一個基本的認(rèn)知,最好是能在腦海中構(gòu)想出整個框架運行的方式,在正式開始之前,先簡單的過一下這張結(jié)構(gòu)圖
抓要點
1. 任務(wù)執(zhí)行單元即圖中的每個task就表示一個基本的任務(wù),有下面幾個要求
統(tǒng)一的繼承關(guān)系(面向?qū)ο蟮脑O(shè)計理念,執(zhí)行同一個角色的類由某個抽象的接口繼承而來)
任務(wù)的執(zhí)行之間是沒有關(guān)系的(即任務(wù)在獨立的線程中調(diào)度執(zhí)行)
2. 任務(wù)隊列在圖中表現(xiàn)很明顯了,在內(nèi)存中會保存一個當(dāng)前所有執(zhí)行的任務(wù)隊列(或者其他的容器)
這個的目的是什么?
任務(wù)腳本更新時,需要卸載舊的任務(wù)(因此可以從隊列中找到舊的任務(wù),并停掉)
任務(wù)腳本刪除時,需要卸載舊的任務(wù)
3. 任務(wù)管理者雖然圖中并沒有明確的說有這么個東西,但也好理解,我們的系統(tǒng)設(shè)計目標(biāo)就是支持多任務(wù)的執(zhí)行和熱加載,那么肯定有個任務(wù)管理的角色,來處理這些事情
其要做的事情就一個任務(wù)熱加載
包括動態(tài)腳本更新,刪除,新增的事件監(jiān)聽
實現(xiàn)卸載內(nèi)存中舊的任務(wù)并加載執(zhí)行新的任務(wù)
4. 插件系統(tǒng)這個與核心功能關(guān)系不大,可以先不care,簡單說一下就是為task提供更好的使用的公共類
這里不詳細展開,后面再說
II. 設(shè)計實現(xiàn)有了上面的簡單認(rèn)知之后,開始進入正題,編碼環(huán)節(jié),省略掉創(chuàng)建工程等步驟,第一步就是設(shè)計Task的API
1. ITask設(shè)計抽象公共的任務(wù)接口,從任務(wù)的標(biāo)識區(qū)分,和業(yè)務(wù)調(diào)度執(zhí)行,很容易寫出下面的實現(xiàn)
public interface ITask { /** * 默認(rèn)將task的類名作為唯一標(biāo)識 * * @return */ default String name() { return this.getClass().getName(); } /** * 開始執(zhí)行任務(wù) */ void run(); /** * 任務(wù)中斷 */ default void interrupt() {} }
前面兩個好理解,中斷這個接口的目的何在?主要是出于任務(wù)結(jié)束時的收尾操作,特別是在使用到流等操作時,有這么個回調(diào)就比較好了
2. TaskDecorate任務(wù)裝飾類,為什么有這么個東西?出于什么考慮的?
從上面可以知道,所有的任務(wù)最終都是在獨立的線程中調(diào)度執(zhí)行,那么我們自己實現(xiàn)的Task肯定都是會封裝到線程中的,在Java中可以怎么起一個線程執(zhí)行呢?
一個順其自然的想法就是包裝一下ITask接口,讓它集成自Thread,然后就可以簡單的直接將任務(wù)丟到線程池中即可
@Slf4j public class ScriptTaskDecorate extends Thread { private ITask task; public ScriptTaskDecorate(ITask task) { this.task = task; setName(task.name()); } @Override public void run() { try { task.run(); } catch (Exception e) { log.error("script task run error! task: {}", task.name()); } } @Override public void interrupt() { task.interrupt(); } }
說明:
上面這個并不是必須的,你也完全可以自己在線程池調(diào)度Task任務(wù)時,進行硬編碼風(fēng)格的封裝調(diào)用,完全沒有問題(只是代碼將不太好看而已)
3. TaskContainer上面兩個是具體的任務(wù)相關(guān)定義接口,接下來就是維護這些任務(wù)的容器了,最簡單的就是用一個Map來保存,uuid到task的映射關(guān)系,然后再需要卸載/更新任務(wù)時,停掉舊的,添加新的任務(wù),對應(yīng)的實現(xiàn)也比較簡單
public class TaskContainer { /** * key: com.git.hui.task.api.ITask#name() */ private static MaptaskCache = new ConcurrentHashMap<>(); /** * key: absolute script path * * for task to delete */ private static Map pathCache = new ConcurrentHashMap<>(); public static void registerTask(String path, ScriptTaskDecorate task) { ScriptTaskDecorate origin = taskCache.get(task.getName()); if (origin != null) { origin.interrupt(); } taskCache.put(task.getName(), task); pathCache.put(path, task); AsynTaskManager.addTask(task); } public static void removeTask(String path) { ScriptTaskDecorate task = pathCache.get(path); if (task != null) { task.interrupt(); taskCache.remove(task.getName()); pathCache.remove(path); } } }
說明
為什么有兩個map,一個唯一標(biāo)識name為key,一個是task的全路徑為key?
刪除任務(wù)時,是直接刪除文件,所以需要維護一個pathCache
維護name的映射,主要是基于任務(wù)的唯一標(biāo)識出發(fā)的,后續(xù)可能借此做一些擴展(比如任務(wù)和任務(wù)之間的關(guān)聯(lián)等)
4. 任務(wù)注冊前面介紹了任務(wù)的定義和裝載任務(wù)的容器,接下來可以想到的就是如何發(fā)現(xiàn)任務(wù)并注冊了,這一塊這里不要詳細展開,后面另起一篇詳解;主要說一下思路
在設(shè)計之初,就決定任務(wù)采用Groovy腳本來實現(xiàn)熱加載,所以有兩個很容易想到的功能點
監(jiān)聽Groovy腳本的變動(新增,更新,刪除),對應(yīng)的類為 TaskChangeWatcher
加載Groovy腳本到內(nèi)存,并執(zhí)行,對應(yīng)的類為 GroovyCompile
5. 執(zhí)行流程有了上面四個是否可以搭建一個原型框架呢?
答案是可以的,整個框架的運行過程
程序啟動,注冊Groovy腳本變動監(jiān)聽器
加載groovy腳本,注冊到TaskContainer
將groovy腳本丟到線程池中調(diào)度執(zhí)行
執(zhí)行完畢后,清除和回收現(xiàn)場
6. 其他當(dāng)然其他一些輔助的工具類可有可無了,當(dāng)然從使用的角度出發(fā),有很多東西還是很有必要的,如
通用的日志輸出組件(特別是日志輸出,收集,檢索,經(jīng)典的ELK場景)
報警相關(guān)組件
監(jiān)控相關(guān)
redis緩存工具類
dao工具類
mq消費工具類
http工具類
其他
III. 其他 0. 相關(guān)博文:
180628-動態(tài)任務(wù)執(zhí)行框架想法篇
180702-QuickTask動態(tài)腳本支持框架整體介紹篇
項目:
https://github.com/liuyueyi/quick-task
1. 一灰灰Blog: https://liuyueyi.github.io/he...一灰灰的個人博客,記錄所有學(xué)習(xí)和工作中的博文,歡迎大家前去逛逛
2. 聲明盡信書則不如,已上內(nèi)容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發(fā)現(xiàn)bug或者有更好的建議,歡迎批評指正,不吝感激
微博地址: 小灰灰Blog
QQ: 一灰灰/3302797840
3. 掃描關(guān)注文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/76460.html
摘要:動態(tài)腳本支持框架之腳本加載執(zhí)行上一篇簡答說了如何判斷有任務(wù)動態(tài)添加刪除或更新,歸于一點就是監(jiān)聽文件的變化,判斷目錄下的文件是否有新增刪除和改變,從而判定是否有任務(wù)的變更接下來的問題就比較明顯了,當(dāng)任務(wù)變更之后,就需要重新加載任務(wù)了,即如何 showImg(https://segmentfault.com/img/remote/1460000015923148); Quick-Task ...
摘要:動態(tài)腳本支持框架之任務(wù)動態(tài)加載前面幾篇博文分別介紹了整個項目的基本架構(gòu),使用說明,以及整體框架的設(shè)計與實現(xiàn)初稿,接下來則進入更細節(jié)的實現(xiàn)篇,將整個工程中核心實現(xiàn)撈出來,從為什么這么設(shè)計到最終的實現(xiàn)給予說明相關(guān)系列博文動態(tài)腳本支持框架整體 showImg(https://segmentfault.com/img/remote/1460000015806174); Quick-Task 動...
摘要:文章鏈接動態(tài)腳本支持框架之使用介紹篇動態(tài)腳本支持框架之使用介紹篇相關(guān)博文動態(tài)腳本支持框架整體介紹篇這個項目主要就是為了解決數(shù)據(jù)訂正和接口驗證不方便的場景,設(shè)計的一個及其簡單的動態(tài)腳本調(diào)度框架,前面一篇整體介紹篇博文,主要介紹了這是 showImg(https://segmentfault.com/img/remote/1460000015698572); 文章鏈接:https://li...
摘要:軟件測試江湖二神兵利器篇在上一篇文章中我們介紹了江湖上流傳的各種軟件測試的武功秘籍和心法,相信看過的小伙伴內(nèi)力得到了很大的提升。功能測試篇功能測試,是軟件測試?yán)锏娜腴T級心法,自然也有與之相對應(yīng)的兵器來發(fā)揮心法的最大功力。 軟件測試江湖(二)神兵利器篇 在上一篇文章中我們介紹了江湖上流傳的各種軟件測試的武功秘籍和心法,相信看過的小伙伴內(nèi)力得到了很大的提升。如果沒有,一定是你看的姿勢不對,...
閱讀 3342·2021-11-23 09:51
閱讀 842·2021-10-14 09:43
閱讀 3384·2021-09-06 15:00
閱讀 2556·2019-08-30 15:54
閱讀 2697·2019-08-30 13:58
閱讀 2033·2019-08-29 13:18
閱讀 1519·2019-08-27 10:58
閱讀 658·2019-08-27 10:53