日前,做了一個小練習,採用的hessian架構實現的網路訪問,其中在傳統的hessian網路訪問請求中加入了一些非同步元素。如為傳統的hessian請求的簡略圖
我們以登入狀態例,來看看代碼的流程:
請求:
介面中阻塞式登入方法,自己代碼:
/**登入--登入**/public User login(String userName,String passWord,long id,int typeId) throws InteractionException;
產生通過HessianProxyFactory產生HessianProxy的方法,看源碼:
public Object create(Class<?> api, URL url, ClassLoader loader) { if (api == null) throw new NullPointerException("api must not be null for HessianProxyFactory.create()"); InvocationHandler handler = null; handler = new HessianProxy(url, this, api); return Proxy.newProxyInstance(loader, new Class[] { api, HessianRemoteObject.class }, handler); }
得到HessianProxy以後,調用裡面的invoke方法即login的代理方法實現登入簡單的請求,看源碼。
public Object invoke(Object proxy, Method method, Object []args) throws Throwable { ....... AbstractHessianOutput out = _factory.getHessianOutput(os); out.call(methodName, args); //將登入方法名和參數寫出去 out.flush(); ........ }
通過得到的HessianProxy直接調用第一步中的login方法即可,自己代碼:
proxy.login("duancanmeng","123");
在上面的基礎假如一些非同步元素,
如何來體現非同步性?
無非就是開線程,那到底該如何開呢?在哪裡開呢?開什麼樣的線程?
首先想到的應該就是把HessianProxy中的invoke放入新開的線程中處理,這是最基本的。直接new Thread行嗎?
當然可以,於是可以寫一個類HessianNewProxy繼承HessianProxy,複寫invoke方法,這裡面可以做一些檢查,如果判斷是非同步,則在新開的線程中調用父類的invoke方法,否則,直接在主線程中調用父類的invoke方法:
HessianNewProxy:
invoke(){ if(非同步){ new Thread(){ run(){ super.invoke(); } }.start(); }else{ super.invoke(); }}
可是在android中並不推薦直接new Thread來執行非同步請求(考慮到一些介面重新整理的問題),android內部封裝了自己的非同步任務類AsynTask。可是普通的java項目卻並沒有如此的非同步任務類,要想實現普通java項目也能和android項目一樣,在方法執行前和執行後都做一些操作的話,在這裡,我們可以把線程實現的方式作為介面抽出來交給使用者自己實現,於是,在invoke的非同步塊中,用非同步任務執行器來執行非同步任務,但是具體的實現方式交給使用者視情況處理。上面的代碼可以改成:
invoke(){ if(非同步){ 自己視情況的線程方式(HessianAsynTask task); }else{ super.invoke(); }}
其中HessianAsynTask:
package com.pccw.hessian.support.client;/** * 任務執行監聽器. * 該監聽器只應該在UI線程中建立 * @param <R>任務成功執行返回結果類型 * @param <E>任務執行拋出的異常類型 */public interface HessianAsynTask<R,E extends Throwable> {R doInBackground() throws E;/** * 任務執行過程中出現異常將調用此方法 * [執行在UI線程] */void onExceptionOccured(E e);/** * 任務執行成功將調用該方法,Result是任務結果 */void onExecuteSuccess(R result);/** * 任務成功執行[或者發生異常]後都將執行該方法 * @param context * @param uriKey */void onFinally(R result);}
這樣的話我們只需要在自己實現的線程方式中,控制HessianAsynTask中方法執行的順序,則既照顧到了android項目,也照顧到了java項目。而線程的實現方式如何交給使用者自己實現?這裡也需要定義一個非同步任務執行器的介面HessianAsynTaskExecuter,其代碼如下:
HessianAsynTaskExecuter:
package com.pccw.hessian.support.client;/** * 非同步任務執行器 * */public interface HessianAsynTaskExecuter<R,E extends Throwable> {public void execute(HessianAsynTask<R,E> executer);}
那麼,前面HessianNewProxy中invoke方法可以改為:
invoke(){ if(非同步){ HessianAsynTaskExecuter.execute(HessianAsynTask); }else{ super.invoke(); }}
我們只關心非同步任務執行器的實現即可,如此一來,不論android項目還是java項目,在調用真正業務方法之前或者之後的一些操作,都統一在HessianAsynTask中可以處理了。
比如,我如果是java項目,我可以在HessianAsynTaskExecute的實作類別中可以new Thread來控制HessianAsynTask中方法的實現順序來達到前置和後置操作:
execute(HessianAsynTask task){ new Thread(){try{ task.doInBackground(){ login(); }; task.onExecuteSuccess();}}catch(){ task.onExceptionOccured(); }finally{ task.onFinally();} }}
如果是android項目,則如下:
execute(final HessianAsynTask<R,E> executer) {new AsyncTask<Void, Void, Exception, R>(){@Overrideprotected R doInBackground(Void... params) throws Exception {return executer.doInBackground();}@Overrideprotected void onPostExecute(R result) {executer.onExecuteSuccess(result);executer.onFinally(result);}@SuppressWarnings("unchecked")@Overrideprotected void onExceptionOccured(Exception e) {executer.onExceptionOccured((E) e);executer.onFinally(null);}}.execute();}}
因此可以看出HessianAsynTaskExecute是結合HessianAsynTask配套使用來適應不同的情況。
具體的流程看如:
HessianAsynTaskExecuter:非同步任務執行器,用來執行請求中傳過來的非同步任務,比如非同步登入
HessianTaskExcuterObserver:任務執行觀察器,用來監視任務(包括非同步和非非同步任務)的執行情況,其中可以做一些緩衝、資源等處理
HessianAsynTask:非同步任務,主要結合HessianAsynTaskExecuter使用,作為參數傳入執行器的方法中用來執行。
TaskExecuteListener:任務執行監聽器,監聽非同步任務的執行情況,其中可以做一些緩衝、資源的處理等
1、登入請求
介面中阻塞式登入方法:
/**登入--登入**/public void login(String userName,String passWord,long id,int typeId,TaskExecuteListener<User, InteractionException> listener);
2、factory產生proxy。
remoteService = proxyFactory.create(RemoteService.class, url, new CMSAsynTaskExecuter<Object, Exception>(),new CMSExceptionHandler(),new CMSTaskExcuterObserver(SharedPreferencesUtlis.getAppSharedPreferences(context)),new CMSConnectionObserver(SharedPreferencesUtlis.getAppSharedPreferences(context)));
3、判斷是否為非同步請求,這裡通過login方法中的參數來判斷,如果是非同步,則裡面傳入一個TaskExecuteListener。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{mTaskExecuteObserver.onPerExecute(this,proxy,method, args);/** * =========================================非同步任務塊 */TaskExecuteListener<Object,Throwable> taskExecuteListener=null;if(args!=null && args.length > 0 && args[args.length-1] instanceof TaskExecuteListener){//檢測該方法是否為非同步方法呼叫,檢測的依據是改方法的參數列表中最後一個參數類型是TaskExecuteListenertaskExecuteListener=(TaskExecuteListener<Object,Throwable>) args[args.length-1];args=SupportUtils.copyOfRange(args, 0, args.length-1);method=getNoAsynMethod(method);//將方法和參數都換成非非同步方法和參數taskExecuteListener.onPerExecute(method, args);}if(taskExecuteListener!=null){//如果需要向遠程擷取資料且發現為非同步任務,那麼啟動非同步方法呼叫執行任務,本方法直接返回nulldoInvokeAsyn(proxy, method, args,taskExecuteListener);return null;}else{//直接阻塞式向遠程服務端請求資料Object result=null;Throwable e=null;try { result=super.doInvoke(proxy, method, args); mTaskExecuteObserver.onExecuteSuccess(this,proxy,method, args, result);return result;} catch (Throwable e1) {e=exceptionHandler.parseException(e1);Object secondResult=mTaskExecuteObserver.onExceptionOccured(this,proxy,method, args, e);//如果異常挽救措施成功那麼該任務仍是成功的 mTaskExecuteObserver.onExecuteSuccess(this,proxy,method, args, secondResult);return secondResult;}finally{mTaskExecuteObserver.onFinally(this,proxy,method, args, result,e);}}}
4、通過非同步任務執行器執行非同步任務
@SuppressWarnings("unchecked")private void doInvokeAsyn(final Object proxy, final Method method, final Object[] args,final TaskExecuteListener<Object,Throwable> taskExecuteListener){((HessianNewProxyFactory)_factory).getAsynTaskExecuter().execute(new HessianAsynTask<Object,Throwable>() {private Throwable mThrowable;private Object mResult;@Overridepublic Object doInBackground() throws Throwable {return doInvoke(proxy, method, args);}@Overridepublic void onExceptionOccured(Throwable exception) {exception=exceptionHandler.parseException(exception);Object result=null;try {result=mTaskExecuteObserver.onExceptionOccured(HessianNewProxy.this,proxy, method, args, exception);onExecuteSuccess(result);} catch (Throwable e) {mThrowable=e;taskExecuteListener.onExceptionOccured(method, args, e);}}@Overridepublic void onExecuteSuccess(Object result) {mResult=result;mTaskExecuteObserver.onExecuteSuccess(HessianNewProxy.this,proxy, method, args, result);taskExecuteListener.onExecuteSuccess(method, args, result);}@Overridepublic void onFinally(Object result) {mTaskExecuteObserver.onFinally(HessianNewProxy.this,proxy, method, args, mResult, mThrowable);taskExecuteListener.onFinally(method, args, mResult);}});}}
5,6、HessianAsynTask在第四步中的代碼可以看出是作為一個參數傳入,同時這個參數中還需要一個監聽器參數TaskExecuteListener,TaskExecuteListener只是針對非同步請求的監聽而且範圍很小,只是針對該請求,TaskExecuteListener代碼如下:
/** * 任務執行監聽器. * 該監聽器只應該在UI線程中建立 * @param <T>任務成功執行返回結果類型 */public interface TaskExecuteListener<R,E extends Throwable> {/** * 在任務開始前執行該方法,你可以在此方法做一些初始化工作 * [執行在UI線程] */void onPerExecute(Method method, Object[] args);/** * 任務執行過程中出現異常將調用此方法 * [執行在UI線程] */void onExceptionOccured(Method method, Object[] args,E e);/** * 任務執行成功將調用該方法,Result是任務結果 */void onExecuteSuccess(Method method, Object[] args,R result);/** * 任務成功執行[或者發生異常]後都將執行該方法 * @param context * @param uriKey */void onFinally(Method method, Object[] args, R result);}
7、HessianTaskExcuterObserver是一個整體的監聽器,針對任何要求方法,而且不論是非同步還是非非同步,裡面可以做一些緩衝的設定,比如在很久不進行操作之後,然後擷取資料之前判斷緩衝中是否有登陸使用者的資訊,如果有,則進行擷取資料,如果沒有,則進行登入。
具體代碼:
public interface HessianTaskExcuterObserver {/** * 在任務開始前執行該方法,你可以在此方法做一些初始化工作 * [執行在UI線程] */void onPerExecute(HessianProxy InvocationHandler,Object proxy,Method method, Object[] args);/** * 在任務執行前進行一些檢測 * @return 如果為true則沒有問題,繼續執行,如果為false則檢測有問題,停止執行並執行onCheckFalseReturn */boolean onPerExecuteCheck(HessianProxy InvocationHandler,Object proxy,Method method, Object[] args);/** * 在任務執行前進行一些檢測, 如果為false則檢測有問題,則執行onCheckFalseReturn並且任務停止執行 */ObjectonCheckFalseAndReturn(HessianProxy InvocationHandler,Object proxy,Method method, Object[] args);/** * 任務執行過程中出現異常將調用此方法 * @return 你可以在此方法中繼續throw e,但是你仍有機會返回合適的任務執行結果 */Object onExceptionOccured(HessianProxy InvocationHandler,Object proxy,Method method, Object[] args,Throwable e) throws Throwable;/** * 任務執行成功將調用該方法,Result是任務結果 */void onExecuteSuccess(HessianProxy InvocationHandler,Object proxy,Method method, Object[] args,Object result);/** * 任務成功執行[或者發生異常]後都將執行該方法 */void onFinally(HessianProxy InvocationHandler,Object proxy,Method method, Object[] args, Object result,Throwable e);}
該包的源碼的:http://download.csdn.net/detail/duancanmeng/4561246