背景
在《我們的應用系統是如何支撐千萬級別用戶的》隨筆中已經從“宏觀”角度去介紹了整個應用系統的布局。組件化是整個系統由頭到尾都始終堅持的一個設計原則,其中“SOA組件化容器”也是我們應用系統比較特別的一點。好東西肯定要分享,當然,這個好還只停留在自戀當中。
主題
上圖為整個SOA容器(即WEB容器)的透析圖。其中各個(黃色)組件的執行流程就是整條業務線程的執行流程。例如在我們應用系統中主要包括會話組件、安全攔截組件、業務驗證組件、業務解析組件、業務服務組件、業務響應組件、日志組件等。也就是這些組件組成了整個業務線程的生命周期。接下來對SOA容器的各個組成部分進行一一介紹。
SOA組件配置文件
配置文件就是組件執行引擎的依賴,有點類似於Spring配置文件的概念,下面是配置文件的一個例子:
<?xml version="1.0" encoding="UTF-8"?>
<soabean id=”session” class=”com.soa.session” order=”1”/>
<soabean id=”security” class=”com.soa. security” order=”2”/>
<soabean id=”validate” class=”com.soa.validate” order=”3”/>
<soabean id=”analysis” class=”com.soa.analysis” order=”4”/>
<soabean id=”service” class=”com.soa.service” order=”5”/>
<soabean id=”response” class=”com.soa.response” order=”6”/>
<soabean id=”logger” class=”com.soa.logger” order=”7”/>
其中soabean為SOA容器組件,id為組件的唯一標識,class為組件的類路徑,order為組件的執行順序。
SOA組件執行引擎
執行引擎就是整個SOA組件容器的發動機,容器初始化時需要加載SOA組件配置文件信息並通過反射生成各組件實例根據序號(order)依序存放在SOA組件單例隊列容器里。當業務請求到達SOA容器時,執行引擎循環執行單例隊列容器里面的組件。
/*偽代碼*/
Loop singleSOABeanList: //循環組件單例隊列容器
SOABean.handle(); //組件執行
SOA組件單例隊列容器
這是一個存放着SOA組件實例的單例隊列容器,隊列的順序依賴於配置文件的order值,按隊列容器按order值升序排序,order值越小的組件越優先執行。
ThreadLoal(線程本地變量)
這是整個線程生命周期的本地變量,主要存儲的是會話信息,而這個會話信息就是各組件解耦的關鍵所在,貫穿了所有組件的執行。會話信息主要包含着以下字段:
Class Session{
serssionId //會話標識
seviceName //請求服務標識,如SOA_001_001,可自定義業務規則
retCode //業務響應標識
retDesc //業務響應描述
isGone=true //線程主流程執行信號(true/false)
soaLogger //SOA容器組件日志跟蹤器
reqJson //請求參數報文
respJson //響應參數報文
HTTPRequest實例
HTTPRespone實例
Userinfo //用戶信息
……
}
此會話跟HTTP會話的作用是一樣的,主要是維護用戶不同請求的關聯關系,同時還是各組件的解耦的關鍵所在。
SOA組件
上圖中的黃色組件為各SOA容器的業務組件,業務組件需要實現SOA組件接口。
public interface SOAInterface {
public void handle();
}
組件是一個獨立體,必須管理好自己所以異常信息,可通過會話實體記錄和跟蹤會話的運行情況。組件又分為主流程組件和輔助組件,主流程組件是通過會話的線程主流程執行信號(isGone)來跟蹤主業務流程的執行情況,如果某主業務流程組件發生異常或業務失敗,則通過session.setIsGone = false告訴后續的主流程組件不需要執行了:
/*主流程組件偽代碼*/
Class SubGroup implement SOAInterface(){
try{
If(session.isGone){
operations
…
If(operation false){
session.setIsGone = false;
}
}
}catch(Exception e){
session.setExceptionLog;
session.setIsGone = false;
}
}
在我們應用中,主流程組件有會話組件、請求解析組件、業務處理組件、請求業務響應組件等。而輔助組件有黑名單攔截組件,日志組件等。輔助組件的異常不會導致整條業務線程的奔潰,遇到異常,不會對主線程的運行標識(isGone)進行干預,以免影響整條主業務線程的正常服務。例如黑名單攔截,如果就因為黑名單組件異常失敗,而停止系統所有業務對外提供服務,那有點說不過去。其實說白了,還是根據自己業務而定。對於一些比較敏感的系統組件,可以通過實時異常監控組件去跟蹤來彌補日志異常信息監控緩慢的缺點。例如可以利用“發布訂閱系統”:
/*會話記錄組件異常信息偽代碼*/
session.setExceptionLog(){
ExceptionLog;
PubSubMonitor.publish(exceptioninfo); //通過發布訂閱監控組件實時監控
}
總結
不難理解,各個組件就是線程棧的組成部分。SOA組件化容器把整個業務請求流程的各個組成部分都封裝成組件化形式執行,例如會話解析、請求參數解析、業務邏輯處理、請求業務響應、日志記錄等業務主要流程。有利於系統日后的擴展性和維護性。這個SOA容器其實有點類似於企業服務總線(ESB)的概念,也同樣支持類似Spring的AOP功能,畢竟在一條垂直的業務線程上,可通過組件配置文件在隨意一個橫切面插入其他操作組件。無論SOA容器組件還是服務層(SOA容器業務邏輯處理組件)的業務服務組件,都是通過反射實現生產單例使用,也有點類似於Spring的IOC概念。在這里我主要還是提供想法和思路,只有思路是通用的,還是建議思路+具體業務的實現才能發揮系統的最大性能。DIY過程最好不要脫離組件化和簡單化的設計原則,當然,定義=限制,不同人都有不同的可能,歡迎評論交流。