上篇文章主要講了設計 Phoenix 框架前的遇到的問題和設計框架的思路 《 Phoenix 框架 從 0 到 1 設計業務並發框架 小米商城產品站革新之路》,本篇文章主要講一下如何設計框架的。
不死鳥並發框架,是自動構建有向圖按照深度進行構建並發組並進行並發調用結果的框架。
產品站業務靜態接口與動態接口都需要調用大量的後臺服務進行獲取數據進行業務編排,而各個並發調用之間又相互存在依賴,採用並發組設計拆解依賴,同時並發控制調用,BO to DTO 採用統一的 Transfer 層進行設計,開發人員只需要關係定義每次調用事件的 Task 和 Transfer 代碼邏輯的書寫,直接返回業務數據。
名詞解釋#
- PhoenixFramework 不死鳥(鳳凰)框架,此業務並發框架的名稱;
- Task 在業務並發中定義一次調用,可以是 HTTP、DUBBO 或者是 Redis 獲取、MySQL 讀庫操作;
- Transfer 在業務定義中是一個子業務模塊的轉換邏輯將 BO 數據轉換為 DTO 數據;
Task 與 Trans 註解#
怎麼定義 Task#
在框架設計之初,我們內部有兩種方案,一種是繼承抽象類實現的方式,Task 通過繼承實現 PhoenixTask 類實現定義 Task,另外一種是採用註解的方式,將每個 Task 都定義成具有強約束的 Task ,並且把詳細的描述信息在註解中定義,給開發人員一目了然的設計思路。
經過內部討論,我們選擇了 Java 優秀的語言特性,註解的方式聲明定義 Task ,這樣的定義使得代碼簡潔明了,也有利於通過 Spring Bean 收集工具來收集我們的定義。
/**
* PhoenixTask
* 任務註解
*
* @author debuginn
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface PhoenixTask {
String taskName(); // 任務名稱
String[] beforeTaskName() default {}; // 前置任務
String[] filterPlatform() default {}; // 過濾渠道,黑名單
String[] taskBoName(); // 任務生成的 BO 數據 用來校驗衝突
}
PhoenixTask
註解定義非常簡單:
taskName
用來標識任務名稱,採用枚舉,強制約束命名的唯一;beforeTaskName
前置任務,前面講到每個任務都是一次事件,區分前置任務是需要在並發調用的時候等待結果的返回,之後用來作為此 Task 調用的前置參數;filterPlatform
過濾渠道,也就是黑名單的功能,但請求渠道在 Task 中聲明了黑名單,在並發執行的時候就自動屏蔽掉執行;taskBoName
任務轉化為 BO 的數據,通過接口調用或者中間件獲取數據,轉化為 Transfer 層使用的數據,在框架層做數據參數校驗;
怎麼定義 Trans#
Trans 是 Transfer 的簡稱,同樣和 Task 設計一樣,也是採用註解的方式定義:
/**
* PhoenixTrans
* 業務編排註解
*
* @author debuginn
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface PhoenixTrans {
String transName(); // 業務編排塊名稱
String apiName(); // 執行 使用並發 api
String[] tasks() default {}; // 依賴的 task 任務
}
PhoenixTrans
註解定義同樣非常簡單:
transName
用來標識業務編排塊名稱;apiName
用來區分這個 Transfer 業務編排是隸屬於哪個並發 API 所屬的;tasks
就是定義依賴的 Task 任務有哪些,一個業務編排可能會利用 n 個 Task 返回的 BO 數據進行編排;
大家在這裡可能會比較疑惑,為啥 Task 中沒有定義 apiName 而是 Transfer 中定義的,是因為在設計中,為了後續 Task 可以被 n 個並發 API 共・用,這樣在 Transfer 定義了 apiName,之後通過 tasks 定義依賴的 Task 就可以推斷出這個 Task 目前是被哪一個並發 API 使用的。
怎麼收集 Task 和 Trans#
自定義了 PhoenixTask
和 PhoenixTrans
註解,通過聲明一個 AnnotationProcessor
繼承 BeanPostProcessor
來進行收集定義的註解。
- 首先是根據註解類收集上來對應的 Task 和 Trans;
- 根據不同的 Trans 劃分不同的 API,收集不同 API 依賴的 Task;
- 按照 Trans 是否進行依賴過濾使用到的 Task;
- 根據 Task 之間的相互依賴關係,將 Task 進行分組;
這樣就完成了對框架的分層與自動構建的設計,框架的設計主要的是要思考如何將實際業務中使用的模塊抽象化設計,同時要思考框架的擴展性與強約束性。
結尾#
本篇文章主要講解我如何將業務與調用關係進行抽象成 Trans 與 Task 的,接下來我將講述並發框架並發線程池的核心設計、配置化思考、監控設計以及自動構建算法等系列文章。
如果你感興趣,推薦關注公眾號或訂閱本站,歡迎互動與交流,讓我們一起變得更強~