0%

HandlerExceptionResolver

HandlerExceptionResolver异常处理

HandlerExceptionResolver是专门进行异常处理的,在render之前进行工作,从异常中解析出ModelAndView

1
2
3
4
5
6
public interface HandlerExceptionResolver {

ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);

}
  • DefaultHandlerExceptionResolver 根据不同类型的异常来进行解析,response.sendError设置不同的错误码
  • ExceptionHandlerExceptionResolver 使用@ExceptionHandler注解的方法来进行异常解析
  • ResponseStatusExceptionResolver 解析有@ResponseStatus注解的异常
  • SimpleMappingExceptionResolver 通过配置的异常类和View的映射关系来解析异常

ExceptionHandlerExceptionResolver

我一般都是使用@ExceptionHandler注解,所以就以ExceptionHandlerExceptionResolver为例

所有的HandlerExceptionResolver实现类都是去重写resolveException方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver#resolveException
@Override
public ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
// 判断当前HandlerExceptionResolver是否可以解析
if (shouldApplyTo(request, handler)) {
// 判断是否禁用缓存,如果禁用缓存的话,设置响应头
prepareResponse(ex, response);
// 具体的处理逻辑
ModelAndView result = doResolveException(request, response, handler, ex);
if (result != null) {

// Explicitly configured warn logger in logException method.
logException(ex, request);
}
return result;
}
else {
return null;
}
}

shouldApplyTo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver#shouldApplyTo
@Override
protected boolean shouldApplyTo(HttpServletRequest request, Object handler) {
if (handler == null) {
return super.shouldApplyTo(request, handler);
}
else if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
handler = handlerMethod.getBean();
return super.shouldApplyTo(request, handler);
}
else {
return false;
}
}

// org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver#shouldApplyTo
protected boolean shouldApplyTo(HttpServletRequest request, Object handler) {
if (handler != null) {
// mappedHandlers是处理器的集合
if (this.mappedHandlers != null && this.mappedHandlers.contains(handler)) {
return true;
}
// mappedHandlerClasses是处理器类型的集合
if (this.mappedHandlerClasses != null) {
for (Class<?> handlerClass : this.mappedHandlerClasses) {
if (handlerClass.isInstance(handler)) {
return true;
}
}
}
}
// Else only apply if there are no explicit handler mappings.
return (this.mappedHandlers == null && this.mappedHandlerClasses == null);
}

doResolveException

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
protected final ModelAndView doResolveException(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

return doResolveHandlerMethodException(request, response, (HandlerMethod) handler, ex);
}

protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod, Exception exception) {
// 找到处理异常的方法
ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
if (exceptionHandlerMethod == null) {
return null;
}
// 设置argumentResolvers和returnValueHandlers
exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);

ServletWebRequest webRequest = new ServletWebRequest(request, response);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();

try {
if (logger.isDebugEnabled()) {
logger.debug("Invoking @ExceptionHandler method: " + exceptionHandlerMethod);
}
Throwable cause = exception.getCause();
if (cause != null) {
// Expose cause as provided argument as well
// 执行exceptionHandler方法解析异常
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, cause, handlerMethod);
}
else {
// Otherwise, just the given exception as-is
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, handlerMethod);
}
}
catch (Throwable invocationEx) {

// Continue with default processing of the original exception...
return null;
}

if (mavContainer.isRequestHandled()) {
return new ModelAndView();
}
else {
ModelMap model = mavContainer.getModel();
HttpStatus status = mavContainer.getStatus();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, status);
mav.setViewName(mavContainer.getViewName());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
}