目录
序言
在使用SpringMVC的过程中,应用系统通常都会有需要统一处理未捕获异常的需求,为了将异常处理的逻辑与业务逻辑代码分离开,SpringMVC提供了@ExceptionHandler 统一异常处理的方式。@ExceptionHandler 是配合@ControllerAdvice一起使用的,这样我们就可以在集中的地方处理未知异常,打印对应日志,封装返回结果等。
@ExceptionHandler 所处位置
首先我们知道所有的事情都是发生在DispatcherServlet这个类中,然后在initStrategies中完成了异常处理器的初始化:
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context); //初始化异常处理器
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
然后经过一系列的RequestMapping映射找到handler并调用后返回了结果,而这个结果有可能是一个异常对象,所以在调用handler完成后再来对异常进行了统一处理:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//--- 省略一堆代码 ---
try {
//--再省略一堆代码 ---
try {
//--省略几十行代码----
// 调用hander
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//---再省略几行代码 ------
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//魔法就发生在这里
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
//---进行一些其他处理 ---
}
}
在processDispatchResult方法中实现了对异常的处理:
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
//如果handler最终返回的是异常,则调用processHandlerException方法
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
//-----省略了很多代码 -------------
}
而在processHandlerException方法中,最终会使用handlerExceptionResolvers来对异常进行处理:
@Nullable
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler, Exception ex) throws Exception {
request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
ModelAndView exMv = null;
if (this.handlerExceptionResolvers != null) {
//就在这里,使用了handlerExceptionResolvers来处理异常
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
exMv = resolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
}
//----省略了很多代码----------
}
统一异常处理的使用
这里我先描述一下如何使用,直接看代码:
@ControllerAdvice("com.ddd.controller"