最近遇到spring MVC中異常捕獲的問題,比較好奇spring是怎麼catch住exception然後調用exceptionHandler中的方法的。發現真相原來這麼簡單。。。。居然直接用的是try catch。
根據源碼可以看出,要實現異常攔截,可以實現一個類實現HandlerExceptionResolver
和Ordered
接口,後者主要用於排序,在spring容器中申明就可以了。
DispatcherServlet
大家都直到這是在Spring MVC中接收請求並分發請求的一個核心類。
主要注意異常處理器的加載和調用,分別在disaptcherServlet初始化和doDispatch中:
初始化
這個類在初始化時spring會首先調用onRefresh方法
。在這個方法中調用initStrategies()
方法。
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
其中的this.initHandlerExceptionResolvers(context);
就是用於加載異常處理器的。
private void initHandlerExceptionResolvers(ApplicationContext context) {
this.handlerExceptionResolvers = null;
if (this.detectAllHandlerExceptionResolvers) {//默認爲true
Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerExceptionResolvers = new ArrayList(matchingBeans.values());
//根據resolver的order屬性排序
AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
}
} else {
try {
HandlerExceptionResolver her = (HandlerExceptionResolver)context.getBean("handlerExceptionResolver", HandlerExceptionResolver.class);
this.handlerExceptionResolvers = Collections.singletonList(her);
} catch (NoSuchBeanDefinitionException var3) {
;
}
}
if (this.handlerExceptionResolvers == null) {
this.handlerExceptionResolvers = this.getDefaultStrategies(context, HandlerExceptionResolver.class);
if (this.logger.isDebugEnabled()) {
this.logger.debug("No HandlerExceptionResolvers found in servlet '" + this.getServletName() + "': using default");
}
}
}
可以看到,默認情況下會取spring容器中所有HandlerExceptionResolver
類型的bean,如果detectAllHandlerExceptionResolvers
爲false,則取name爲handlerExceptionResolver的bean。
會按照resolver的order屬性排序,放在List<HandlerExceptionResolver> handlerExceptionResolvers
list裏。
doDispatch
- 在覈心方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
中首先依次調用各個攔截器的preHandle
方法. - 然後調用真正controller的適配器HandlerAdapter對象的
handle
方法做真正的業務處理。 最後再依次調用攔截器的
postHandle
方法。這些處理都包在try catch中。
在catch了異常的時候會調用processHandlerException
方法處理異常,這個方法依次調用DispatcherServlet
屬性的handlerExceptionResolvers
裏面的對象的resolveException
方法,如果一個resolver處理結果不爲空就返回。最後還會依次調用攔截器的
afterCompletion
方法
附上Dispatchservlet doDispatch
方法的代碼。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
int interceptorIndex = -1;
try {
boolean errorView = false;
ModelAndView mv;
try {
label276: {
processedRequest = this.checkMultipart(request);
mappedHandler = this.getHandler(processedRequest, false);//根據url在handler的map中取得HandlerExecutionChain 對象,該對象中有一個處理業務的handler和攔截器的list
if (mappedHandler != null && mappedHandler.getHandler() != null) {
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (this.logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
this.logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
int i;
HandlerInterceptor interceptor;
if (interceptors != null) {
for(i = 0; i < interceptors.length; interceptorIndex = i++) {
interceptor = interceptors[i];
if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) { //執行攔截器的preHandle方法
this.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, (Exception)null);
return;
}
}
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());//真執行controller的方法
if (mv != null && !mv.hasView()) {
mv.setViewName(this.getDefaultViewName(request));
}
if (interceptors == null) {
break label276;
}
i = interceptors.length - 1;
while(true) {
if (i < 0) {
break label276;
}
interceptor = interceptors[i];
interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv); //執行攔截器的postHandle方法
--i;
}
}
this.noHandlerFound(processedRequest, response);
return;
}
} catch (ModelAndViewDefiningException var20) {
this.logger.debug("ModelAndViewDefiningException encountered", var20);
mv = var20.getModelAndView();
} catch (Exception var21) {
Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
mv = this.processHandlerException(processedRequest, response, handler, var21);//異常處理,異常處理器註冊在Dispatcherservlet中
errorView = mv != null;
}
if (mv != null && !mv.wasCleared()) {
this.render(mv, processedRequest, response);//渲染view
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + this.getServletName() + "': assuming HandlerAdapter completed request handling");
}
this.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, (Exception)null);
} catch (Exception var22) {
this.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, var22);
throw var22;
} catch (Error var23) {
ServletException ex = new NestedServletException("Handler processing failed", var23);
this.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
throw ex;
} finally {
if (processedRequest != request) {
this.cleanupMultipart(processedRequest);
}
}
}