由hsf框架异常抛出引发的思考


先交待背景,项目使用了HSF框架,Pandora容器,此项目我方作为生产者提供服务给其他第三方调用,在测试过程中,发现接口有不尽人意的地方,以下为具体描述。

假定A作为服务生产者,B作为服务消费者,A提供有接口方法addEntityFile,定义如下

ResultJsonEO<List<EntityResultEO>> addEntityFileJson(EntityFileInputDTO inputDTO);

其中,ResultJsonEO结构如下
public class ResultJsonEO<T>{

public int code;
private String msg;

/**
* 实体对象
*/
private T data;

public String getMsg() {
return msg;
}

public ResultJsonEO<T> setMsg(String msg) {
this.msg = msg;
return this;
}

public T getData() {
return data;
}

public ResultJsonEO<T> setData(T data) {
this.data = data;
return this;
}

public ResultJsonEO<T> setCode(ResultCode resultCode) {
this.code = resultCode.code;
return this;
}

public int getCode() {
return code;
}

public ResultJsonEO<T> setCode(int code) {
this.code = code;
return this;
}

/**
* 调用成功
* @return
*/
public boolean isSuccess() {
return ResultCode.SUCCESS.code == this.code;
}

}

对于调用方来说,根据返回的json对象(泛化)可以得知,不论提供方内部如何异常,能拿到的总是ResultJsonEO对象,并能通过isSuccess()方法得知返回结果是否正常。 实际上,在测试时,我们发现服务内部发生异常后,对方得不到结果,只得到如下异常提示,非常不友好。

java.util.HashMap cannot be cast to xx.common.api.domain.eo.ResultJsonEO

刚开始看到这个报错的时候,很疑惑,因为找遍了代码也没有找到哪里有HashMap转json对象的这种操作,最后才发现这压根就是hsf框架将异常泛化后抛出的,终究还是因为服务内部没有针对异常进行捕获或抛出。

 

这里补充说明一下,如果不考虑统一返回json对象,其实可以做一个全局异常处理,一旦遇到了异常,就统一抛出异常信息,只不过这时对于消费者来说,调用此接口方法时,就需要额外的异常处理。

 

找到了问题原因所在,接下来就是针对性处理。假如是一个传统的ssh项目,或者是一个单纯的springCloud项目(没有用到这种rpc框架),大体结构如下

controller

service

dao

domain

通常都是在service层处理业务逻辑,这一层也负责事务处理,而且在service层是不会进行异常捕获的,避免中断spring事务,异常捕获都是放在controller层里处理,通常都有统一的全局异常捕获处理。此项目中,报上述错误时的大体结构如下

apiservice      接口定义层

apiserviceImpl    接口实现层,主要的业务逻辑均在里面,包括事务处理

dao

domain

首先,想到了一种解决方案,即将apiserviceImpl层拆分,拆分为apiserviceImpl层和service层,主要的逻辑和事务管理均在service层中完成,apiserviceImpl充当一个类似controller层的角色(注意,这里如果把apiserviceImpl充当controller层来看时,service层是一定要拆分出去的,假如不拆分,直接针对apiserviceImpl进行异常捕获,碰到事务时,一旦发生异常,事务就会被中断)。

apiservice

apiserviceImpl

service      专门处理业务逻辑,事务

dao

domain

这样做的好处在于层次清晰,也可以使用全局异常处理,切面面向impl层,唯一的弊端在于所有的impl代码都得调整,进行代码拆分和service注入,改动稍微有点大。

 

最后,采用了Filter的方式,只需要增加一个Filter,继承hsf原有的Filter的onResponse方法。

import com.taobao.hsf.invocation.filter.ServerFilter;

public class HsfServerFilter implements ServerFilter {
  /**
  * @param invocation
  * @param rpcResult
  */
  @Override
  public void onResponse(Invocation invocation, RPCResult rpcResult) {
  Class returnType = invocation.getReturnClass();
  Object appResponse = rpcResult.getAppResponse();
  if(appResponse instanceof Exception) {
  Object re = rpcResult.getAppResponse();
  log.error("methodName:"+invocation.getMethodName()
+"\tmethodArgs:"+invocation.getMethodArgs().toString()
+"\tmethodException:"+re.toString());
  if(returnType.getName().indexOf("ResultDataEO") > -1){
  rpcResult.setAppResponse(ResultDataEO.fail("服务异常,请联系管理员......"));
  }else{
  rpcResult.setAppResponse(ResultJsonResponse.responseErr("服务异常,请联系管理员......"));
  }
  }
  }
}

onResponse方法,无论接口实现类中是否执行成功,此方法总是会执行的,只不过执行成功的情况下,getAppResponse()得到的是正确的返回类,比如ResultJsonEO,失败的情况下则是异常。上面的解决方式则是异常情况下,强制将返回的信息赋值进去。

 

这样一来,代码改动量不大,而且也不会影响事务(onResponse方法区别于前面提到的aop切面实现的方式,切面方式相当于是把实现类里的代码try catch了,而filter中的onResponse方法是在实现类中的方法执行完之后才会进入)。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM