一.背景
在現在的網站中,接入的管道是越來越多了,技術也是越來越先進,WAP, SMS,EMAIL, 傳統的Web, Socket等等,如果連數據庫和LDAP也算接入的話,那在設計之中需要擴展的空間要做到很好很好,才保證在添加新的渠道情況下不需要更多的修改代碼甚至不改代碼的情況。但可能嗎?我想也不可能,但有什麼方式可以更好的解決這種多渠道接入的框架的完美性呢?
二.構架
【圖一】
如圖一所顯示,在現有的所有接入都已經使用上的時候,設計者看的都眼花繚亂了,如果是為了湊份子,那這些程式怎麼寫都可以,而且也肯定可以實現,但維護起來就會比較痛苦,還是回到那個問題,怎麼可以實現更完美?如圖二顯示:
【圖二】
圖二看起來像個八爪的章魚,章魚腿分別連接所有的接入渠道,進行連接所有這些渠道的核心就是這個章魚的頭XMLRouter,Router在此的作用是溝通所有渠道,實現資料的路由,爭強系統在架構上的擴展性和彈性,好處會很多很多。稱為XMLRouter是因為如果不使用XML這種靈活而又規範的語言來做為數據傳輸的媒介,那Router的工作量也同樣會成倍的增加,定義好XML的規範後將為以後的擴展帶來很多好處。
三.思想和模式
XMLRouter的最初想法來自於電腦的主機板和<
>之中的Builder Pattern, 電腦主機板的PCI 插槽定義了PCI的規範,只要你生產的卡符合PCI標準,那你插入到這個主機板上就可以工作, 至於裡面是怎麼工作的則是已經封裝好了. Builder Pattern則是提出將複雜的構建分離開來, 一步一步的進行實現.XMLRouter是將這些複雜的渠道分離開來,一個個的進行表現.
Services思想:為了能和Router進行溝通,在這些渠道接入時必須定義統一的介面,這裡成為Services, 只要符合Services規範的程式就可以接入到Router並進行資料的路由.Factory
模式和Composite模式
XMLRouter在實際的設計中將採用Factory模式產生,Router由RouterFactory生產, 在投入使用時將放置於隊列中,傳遞數據和接收數據以及返回數據都從隊列中取相應的Router來調用,應用了Composite的模式.
四.XML配置文件
XML文件對於Router之中的使用分為兩個部分, 第一個是Router的配置,如:
以下是引用片段: <?xml version="1.0" ?> <services> <!-- database Service --> <service name="database" type="database" class="com.web.service.DBService"> <connector driver="com.microsoft.jdbc.sqlserver.SQLServerDriver" url="jdbc:microsoft:sqlserver://192.168.0.179:1433" user="test" passwd="test" /> </service> <!-- Web Service--> <service name="web" type="web" class="com.web.service.WebService" > <connector /> </service> …… </services> |
這是Router的設定檔, service節點代表需要接入的管道, service節點包含connector子節點, 子節點的設定根據type來區分, 如果是database則包含url, user, passwd,driver等屬性, 如果是socket則包含port, maxthread等屬性, 屬性值可以根據自己的定義來配置.
另一種XML檔案則是XML交易資料檔,用於在所有的services中傳遞資料,每個Services自己包涵一個對應的XML檔,例如webtrans.xml格式如下:
以下是引用片段: <?xml version="1.0" ?> <transaction> <trans name="addDoc" service="database" method="insert"> <property name="createtime" type="timestamp"/> <property name="creatorid" type="long"/> <property name="doctypeid" type="int"/> <property name="docstatusid" type="int"/> </trans> </transaction> |
對應的dbtrans.xml格式如下
以下是引用片段: <trans name="addDoc" table="TDOC_DOCS" method="insert"> <primarykey name="docid" /> <set> <property name="createtime" type="timestamp"/> <property name="creatorid" type="long"/> <property name="doctypeid" type="int"/> <property name="docstatusid" type="int"/> </set> </trans> |
其餘XML則可依這樣的規則來客製化
五.技術實現
RouterFactory
以下是引用片段: package com.web.router; import com.web.platform.Exception.RouterException; import java.util.java/util/Hashtable.java.html" target="_blank">Hashtable; |
以下是引用片段: /** * Router產生和清除的類 */ public class RouterFactory { /** * Router儲存的樹front */ private static java/util/Hashtable.java.html" target="_blank">Hashtable QueuePairFront = null; /** * Router儲存的樹back */ private static java/util/Hashtable.java.html" target="_blank">Hashtable QueuePairBack = null; /** * Router儲存的樹 */ private static java/util/Hashtable.java.html" target="_blank">Hashtable QueueRouter = null; /** * 傳回的XMLRouter */ public static XMLRouter instance = null; /** * Router的定義 */ public static RouterDefine routerdefine = null; /** * Router的ID號碼 */ public static long routeIndex = 0; /** * @roseuid 3F169C21027C */ public RouterFactory() { } /** * 初始化Hashtable和Vector */ public static void initFactory() throws java/lang/Exception.java.html" target="_blank">Exception { QueuePairFront = new java/util/Hashtable.java.html" target="_blank">Hashtable(); QueuePairBack = new java/util/Hashtable.java.html" target="_blank">Hashtable(); QueueRouter = new java/util/Hashtable.java.html" target="_blank">Hashtable(); initRouteDefine(); } /** * 初始化Route的設定 * */ private static void initRouteDefine() throws java/lang/Exception.java.html" target="_blank">Exception { if( routerdefine == null ) routerdefine = new RouterDefine(); routerdefine.loadRouterDef(); } /** * 傳回實例 * @return com.web.router.XMLRouter */ public static XMLRouter getInstance(long index) throws RouterException { return (XMLRouter)QueueRouter.get(new java/lang/Long.java.html" target="_blank">Long(index)); } /** * 產生一個XMLRouter的實例 * @return com.web.router.XMLRouter * @roseuid 3F1618A103BC */ public static XMLRouter popInstance() throws RouterException { routeIndex ++; instance = new XMLRouter(routeIndex); setDefine( instance ); QueueRouter.put(new java/lang/Long.java.html" target="_blank">Long(routeIndex), instance); return instance; } /** * 清空Hashtable,Vector等 * @roseuid 3F1618B203C1 */ private static void freeResource() throws java/lang/Exception.java.html" target="_blank">Exception { QueuePairFront.clear(); QueuePairBack.clear(); QueueRouter.clear(); QueuePairFront = QueuePairBack = QueueRouter = null; } /** * 清除實例 * @param instanceID * @throws Exception */ public static void removeInstance(XMLRouter instance) throws java/lang/Exception.java.html" target="_blank">Exception { instance.clear(); QueueRouter.remove( new java/lang/Long.java.html" target="_blank">Long(instance.getIndex() ) ) ; } /** * Method isNull. * @return boolean */ public static boolean isNull() { …… return false; } } |
以下是引用片段: package com.web.router; import com.web.platform.Exception.RouterException; import com.web.common.*; import java.util.*; import java.lang.reflect.java/lang/reflect/Method.java.html" target="_blank">Method; import java.lang.reflect.java/lang/reflect/Constructor.java.html" target="_blank">Constructor; /** * @author keli * @version 0.0.1 * 平台的關鍵,路由的類別,每個Router將從RouterFactory裡讀取 * Router儲存的樹front,和back,routeIndex,目的是為了能在路由 * 之後可以清除申請的對象。 * Router可以實現同步和非同步的功能. */ public class XMLRouter { /** * Router儲存的樹front */ private static java/util/Hashtable.java.html" target="_blank">Hashtable QueuePairFront = null; /** * Router儲存的樹back */ private static java/util/Hashtable.java.html" target="_blank">Hashtable QueuePairBack = null; /** * 本router的index號碼 */ private long routeIndex = 0; /** * router的設定 */ private RouterDefine define = null; /** * 用來判斷是路由的起迴點 */ private java/lang/String.java.html" target="_blank">String action = ""; /** *此變數只是用於在routeto方法中申請新的class */ private java/lang/String.java.html" target="_blank">String classname = ""; /** */ public XMLRouter(long index) { routeIndex = index; } /** * 路由 * @throws Exception * @roseuid 3F1616BD0186 */ public void routing(Env env) throws RouterException, java/lang/Exception.java.html" target="_blank">Exception { /*如果為起點*/ if( action.equalsIgnoreCase( RouterConstant.CFG_FUNC_ROUTETO ) ) { …… } /*如果為返回點*/ else if( action.equalsIgnoreCase( RouterConstant.CFG_FUNC_ROUTEBACK ) ) { …… } /*否則為錯誤*/ else throw new RouterException("Set Router action error."); } /** * 讀取本Router的id號. * @return long */ public long getIndex() { return routeIndex; } /** * 清除所有物件. * @throws RouterException */ public void clear() throws RouterException { QueuePairFront.remove(new java/lang/Long.java.html" target="_blank">Long(routeIndex)); QueuePairBack.remove(new java/lang/Long.java.html" target="_blank">Long(routeIndex)); /*系統回收*/ java/lang/System.java.html" target="_blank">System.runFinalization(); } /** * 設定本Router的設定. * @param def * @throws RouterException */ public void setDefine(RouterDefine def) throws RouterException { define = def; } /** * 設定action的值 * @param actionName * @throws RouterException */ public void setAction( java/lang/String.java.html" target="_blank">String actionName ) { action = actionName; } } |
Service類別
以下是引用片段: package com.web.common; import com.web.platform.Exception.RouterException; /** * Service的父類,abstract */ public abstract class RouteService { /** */ public RouteService() { } /** * routeTo方法,是交易的起點。 * @param env * @throws RouterException */ public abstract void routeto(Env env) throws RouterException; /** * routeBack,交易的結束點, * @param env * @throws RouterException */ public abstract void routeback(Env env) throws RouterException; /** * routeaccept方法,是交易的接收點,也是routeto的接收函數, * routeaccept為被動交易物件的主要處理函數 * @param env * @throws RouterException */ public abstract void routeaccept(Env env) throws RouterException; /** * routing方法,是Service對外的介面函數 * @throws RouterException */ public abstract void routing() throws RouterException; |
接下來則需要實現所有的Services的類別了,這裡就不做介紹了.
六.說明
這個Router到目前為止只能實現同步的交易, 暫時不支援異步的交易,但由於對Router使用了Composite的模式設計的,實現非同步交易也是可以擴展的,這裡不做詳細分析.