最近遇到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);
}
}
}