在spring,hibernate中异常的处理都交给了spring框架,在hibernate只需要写很少的代码就可以实现异常的控制。
在单元测试代码中:
public final void testFindFunctionById() {
logger.debug("testFindFunctionById");
long l1=System.currentTimeMillis();
String id="4";
Function function=BeanFactory.getInstance().getRightDelegate().findFunctionById(id, state);
long l2=System.currentTimeMillis();
System.out.println("function.getId = "+function.getId());
System.out.println("function.getName = "+function.getName());
System.out.println("function.getProtectFunction = "+function.getProtectFunction());
System.out.println("--------------finish----------------");
System.out.println("一共用时为 : "+(l2-l1));
}
在delegate中接受信息:
public Function findFunctionById(String id, IState state) {
if (DelegateUtil.isNullParam(id, "id", state)) {
return null;
}
Request req = new Request();
req.setServiceName(ServiceConsts.FindFunctionByIdProcessor);
req.setValue("id", id);
try {
Response resp = getDelegate().execute(req);
DelegateUtil.setIState(state, resp);
Function function = (Function) resp.getValue("function");
DelegateUtil.setIState(state, resp);
return function;
} catch (Exception e) {
DelegateUtil.handleException(e, "findFunctionById", state);
return null;
}
}
在delegate中首先对参数做一般的空指针检查,如下面的代码
public static boolean isNullParam(Object paramObject, String paramName,
IState state)
{
if (paramObject == null) {
logger.error("Parameter " + paramName + " is null;");
state.setErrCode(ErrorCode.PARAMETER_ERROR);
return true;
}
return false;
}
如果传值是null的话,在state中设置ErrorCode.PARAMETER_ERROR参数直接返回给客户端,客户端根据不同的ErrorCode可以知道问题的所在,并作出相应的操作。
然后生成一个Request,封装了这次请求的参数,如ServiceName和values。请求分发到相应的service,如 FindFunctionByIdProcessor。Service再将请求分发到service下面的command,command代码如下:
public class FindFunctionById extends Command
{
private FunctionDao dao;
public void setDao(FunctionDao dao) {
this.dao = dao;
}
public void execute(Map params, Map response) throws Exception
{
response.put("function",(Function)dao.getById(Function.class, (String) params.get("id")));
}
……
}
在command中把参数接下来调用dao的方法,并把结果放在response中。在delegate就可以在response中取得结果。
Dao的代码如下:
public Object getById(Class c, Serializable id) {
return getHibernateTemplate().get(c, id);
}
在dao中只是调用了spring的类。这个调用流程没有涉及到异常的捕捉。那它是在哪里处理的呢?看下面的代码
public class SequenceProcessor extends BaseProcessor {
private static Logger logger=Logger.getLogger(SequenceProcessor.class);
public boolean supports(Component component) {
return (component instanceof Command);
}
public void doActivities(Request request,Response resp) throws Exception {
logger.info("SequenceProcessor 流程开始 <-- "+getBeanName() );
Map response = resp.getValues();
Map params = request.getValues();
List activities = getActivities();
for (Iterator it = activities.iterator(); it.hasNext();) {
Component component = (Component) it.next();
logger.info("活动 : " + component.getBeanName());
try {
component.init("");
component.execute(params, response);
component.fini();
} catch (Throwable th) {
ErrorHandler errorHandler = component.getErrorHandler();
if (errorHandler == null) {
logger.info("no Errorhandler for Command "+component.getBeanName() +", run processor Errorhandler and abort Command ");
ErrorHandler processorerrorHandler=getErrorHandler();
if(processorerrorHandler == null){
logger.info("no error handler for this processor, run defaultErrorHandler and abort processor ");
//执行全局的default ErrorHandler;
ErrorHandler defaultErrorHandler=((ErrorHandler)ContextServiceLocator.getInstance().getBean("defaultErrorHandler"));
if(defaultErrorHandler!=null)
defaultErrorHandler.handleError(resp, th);
else{
logger.info("no default errorHandler for this invoke process, abort!!");
}
}else{
// 执行processor级的ErrorHandler;
logger.info("run processor errorHandler and continue");
processorerrorHandler.handleError(resp, th);
}
} else {
logger.info("run Command Errorhandler and continue");
// 执行Component级的ErrorHandler;
errorHandler.handleError(resp, th);
}
}
}
logger.info(" SequenceProcessor 流程结束 -->");
}
}
在service中发生了异常有3个地方可以做切入点来做处理。Command级别,service级别和全局的错误处理器。如果在 command中发生异常,首先查找Command级别的错误处理器,找不到则找service级别的错误处理器,再找不到就找全局的错误处理器,什么也 没有找到异常则继续抛下去一直到客户端。如下面配置文件所示:
<bean id="activity2"
class="org.artemis.workflow.command.Activity2">
<property name="errorHandler">
<ref bean="defaultErrorHandler" />
</property>
</bean>
<!-- error handler -->
<bean id="defaultErrorHandler"
class="com.gsta.eshore.framework.jcf.JCFErrorHandler" />
在activity2中发生异常就会查找defaultErrorHandler来做相应的处理。
public class JCFErrorHandler implements ErrorHandler {
private String beanName;
private static Logger logger=Logger.getLogger(JCFErrorHandler.class);
public void handleError(Response resp, Throwable th) throws Exception{
if (th instanceof ClientException) {
logger.error("JCFErrorHandler is dealing with ClientException errorCode is "+((ClientException)th).getErrorCode(),th);
resp.setReturnCode(Response.APPLICATION_LEVEL_ERROR);
resp.getState().setErrCode(ErrorCode.BUSINESS_ERROR);
throw (ClientException)th;
}
else if (th instanceof GoOnException) {
logger.error("JCFErrorHandler is dealing with GoOnException", th);
} else if(th instanceof JCFException){
logger.error("JCFErrorHandler is dealing with JCFException errorCode is "+((JCFException)th).getErrorCode(),th);
resp.setReturnCode(Response.APPLICATION_LEVEL_ERROR);
resp.getState().setErrCode(ErrorCode.JCF_ERROR);
throw (JCFException)th;
} else if(th instanceof RemoteException){
logger.error("JCFErrorHandler is dealing with RemoteException",th);
resp.setReturnCode(Response.SYSTEM_LEVEL_ERROR);
resp.getState().setErrCode(ErrorCode.SYSTEM_ERROR);
throw (RemoteException)th;
} else if(th instanceof EJBException){
logger.error("JCFErrorHandler is dealing with EJBException",th);
resp.setReturnCode(Response.SYSTEM_LEVEL_ERROR);
resp.getState().setErrCode(ErrorCode.CALL_EJB_ERROR);
throw (EJBException)th;
} else if(th instanceof NullPointerException){
logger.error("JCFErrorHandler is dealing with RemoteException",th);
resp.setReturnCode(Response.APPLICATION_LEVEL_ERROR);
resp.getState().setErrCode(ErrorCode.NULLPOINT_ERROR);
throw (NullPointerException)th;
}
else{
logger.error("JCFErrorHandler is dealing with Exception",th);
resp.setReturnCode(Response.APPLICATION_LEVEL_ERROR);
resp.getState().setErrCode(ErrorCode.SYSTEM_ERROR);
if(th instanceof Exception)
throw (Exception)th;
}
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
}
可以为每一个command或者service定制不同的错误处理器。针对不同的异常来设置不同的errorCode,同时后端的异常不会影响到客户端的操作。
总结:把异常处理抽取出来