spring mvc 的全局異常處理器
@ExceptionHandler
當(dāng)它在一個 controller 內(nèi)部聲明時业踏,它將被用于那個controller(或它的子類)的 @RequestMapping
方法拋出的異常. 你也可以在 @ControllerAdvice 類里面聲明 @ExceptionHandler
方法,它將會處理很多controller的 @RequestMapping
方法拋出的異常. 我的例子就是寫一個異常處理類彻犁,其被@ControllerAdvice
注解玄帕。
例如:
@ControllerAdvice
public class BizExceptionFilter implements Filter {
@ExceptionHandler(value = Exception.class)
public Object handleIOException(Exception e){
log.info("Catch exception", e);
String exceptionName=e.getClass().getName();
ResultExceptionInfoBean resultExceptionInfoBean=getInfoBean(exceptionName);
FResponse rsp = new FResponse<Object>();
rsp.setCode(resultExceptionInfoBean.getCode());
rsp.setMessage(resultExceptionInfoBean.getMessage());
rsp.setData(e);
return rsp;
}
@ExceptionHandler
的value可以設(shè)置一個需要被處理的異常數(shù)組. 如果一個異常被拋出并且包含在這個異常列表中, 然后就會調(diào)用 @ExceptionHandler
方法. 如果沒有設(shè)置value义锥,
那么就會使用參數(shù)里面的異常.
和標(biāo)準(zhǔn)controller的 @RequestMapping 方法很相似, @ExceptionHandler 方法的參數(shù)值和返回值相當(dāng)靈活. 比如說, HttpServletRequest 可以在 Servlet 環(huán)境中被接收, PortletRequest 在 Portlet 環(huán)境中被接收. 返回值可以是 String, 它將解釋為一個視圖, 可以是 ModelAndView 對象, 可以是 ResponseEntity 對象, 或者你可以添加 @ResponseBody 方法直接返回消息.
dubbo的異常處理
由于spring 的全局異常處理只能對http請求有效,所以對于dubbo的調(diào)用不起作用饱搏。
那么為了實(shí)現(xiàn)對dubbo調(diào)用異常的處理究反,我們可以使用dubbo的攔截擴(kuò)展.
具體配置方式詳見 API.
將擴(kuò)展方法寫到spring 的全局異常處理器中,使其繼承Filter舟奠,然后配置服務(wù)方調(diào)用攔截。
當(dāng)服務(wù)被調(diào)用時就會執(zhí)行該方法房维。
例如:
@ControllerAdvice
public class BizExceptionFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
log.debug("BizExceptionFilter:{},{}", invoker.getInterface(),
JsonUtil.jsonFromObject(invocation.getArguments()));
Result result = invoker.invoke(invocation);
Object realResult = result.getValue();
FResponse rsp = new FResponse<Object>();
if (result.hasException()) {
try {
ExceptionHandlerMethodResolver resolver=new ExceptionHandlerMethodResolver(this.getClass());
Exception exception=(Exception) result.getException();
Method method=resolver.resolveMethod(exception);
realResult = method.invoke(this, exception);
return new RpcResult(realResult);
} catch (Throwable e) {
log.error("Exception handler error. Caused Exception:{}", result.getException());
}
}
rsp.setCode("0000");
rsp.setMessage("Success");
rsp.setData(realResult);
return new RpcResult(rsp);
}
@ExceptionHandler(value = NullPointerException.class)
public Object handleIOException(NullPointerException e){
log.info("Catch exception", e);
String exceptionName=e.getClass().getName();
ResultExceptionInfoBean resultExceptionInfoBean=getInfoBean(exceptionName);
FResponse rsp = new FResponse<Object>();
rsp.setCode(resultExceptionInfoBean.getCode());
rsp.setMessage(resultExceptionInfoBean.getMessage());
rsp.setData(e);
return rsp;
}
@ExceptionHandler(value = IndexOutOfBoundsException.class)
public Object handleIOException(IndexOutOfBoundsException e){
log.info("Catch exception", e);
String exceptionName=e.getClass().getName();
ResultExceptionInfoBean resultExceptionInfoBean=getInfoBean(exceptionName);
FResponse rsp = new FResponse<Object>();
rsp.setCode(resultExceptionInfoBean.getCode());
rsp.setMessage(resultExceptionInfoBean.getMessage());
rsp.setData(e);
return rsp;
}
解析:
Result result = invoker.invoke(invocation);
這行代碼之前的代碼沼瘫,是在服務(wù)被調(diào)用錢執(zhí)行,之后的代碼是在服務(wù)被調(diào)用后執(zhí)行咙俩。
Object realResult = result.getValue();
獲得執(zhí)行結(jié)果.
result.hasException()
是否拋出了異常.
2017-3-15 更新
Exception exception=(Exception) result.getException();
這行代碼的作用是獲得此類中被@ExceptionHandler
注解的方法。
Method method=resolver.resolveMethod(exception);
這行代碼的作用是從被@ExceptionHandler
注解的所有方法中找出value為exception的方法對象歌焦。
realResult = method.invoke(this, exception);
執(zhí)行這個方法飞几。
如圖:
6D14283E-035B-443E-9FDA-276DA93643AB.png
這樣保持了和spring 的全局異常處理一致,即被@ExceptionHandler
注解的方法去處理異常。
spring 相關(guān)源碼如下:
Paste_Image.png
測試:
我在服務(wù)類中直接拋出了異常独撇。
順利執(zhí)行: