日前,做了一个小练习,采用的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>(){
@Override
protected R doInBackground(Void... params) throws Exception {
return executer.doInBackground();
}
@Override
protected void onPostExecute(R result) {
executer.onExecuteSuccess(result);
executer.onFinally(result);
}
@SuppressWarnings("unchecked")
@Override
protected 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){//检测该方法是否为异步方法,检测的依据是改方法的参数列表中最后一个参数类型是TaskExecuteListener
taskExecuteListener=(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){//如果需要向远程获取数据且发现为异步任务,那么启动异步方法执行任务,本方法直接返回null
doInvokeAsyn(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;
@Override
public Object doInBackground() throws Throwable {
return doInvoke(proxy, method, args);
}
@Override
public 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);
}
}
@Override
public void onExecuteSuccess(Object result) {
mResult=result;
mTaskExecuteObserver.onExecuteSuccess(HessianNewProxy.this,proxy, method, args, result);
taskExecuteListener.onExecuteSuccess(method, args, result);
}
@Override
public 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并且任务停止执行
*/
Object onCheckFalseAndReturn(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.youkuaiyun.com/detail/duancanmeng/4561246