1.问题
在进行日志记录的时候,使用了filter过滤器。想当然的认为在过滤器中捕捉到所有异常,然后记录日志。结果是发生异常后,过滤器中无法捕捉到,异常已经被其它程序捕捉。到底是为什么了,于是本人稍微探究了一下这个过程;
2.简介
2.1.http请求的调用过程
2.2.全局异常处理器结构
2.3.运行过程说明
- 项目启动,spring加载全局异常处理器
- http请求,被filter拦截,调用filterChain.dofilter(),经过一系统的过滤器链。最后达到spring的DispatcherServlet;
- DispatcherServlet调用对应的handler(Controller)处理业务逻辑;
- 没有异常则返回到过滤器链,执行filterChain.dofilter()后面的代码;
- 如果发生异常,则调用异常处理器进行处理异常;
- 调用DefaultErrorAttributes,把异常存放到HttpServletRequest和WebRequest中;
- 调用HandlerExceptionResolverComposite。实际上它只是其它异常处理器的组合,它会按顺序交给其它异常处理器处理,直到能处理当前异常;
- 调用ExceptionHandlerExceptionResolver,获取用户配置的全局异常处理器处理异常;
- 调用ResponseStatusExceptionResolver,处理ResponseStatusException和@ResponseStatus标注和自定义异常;
- 调用DefaultHandlerExceptionResolver,处理常见异常,返回http异常码;
- 如果异常已经被处理,则正常返回。返回到过滤器链,执行filterChain.dofilter()后面的代码;
- 如果异常不能被处理,则抛出异常。返回到过滤器链,执行catch里面的代码;
3.运行过程源码
3.1.项目启动
A.WebMvcConfigurationSupport初始化全局异常处理器
@Bean
public HandlerExceptionResolver handlerExceptionResolver() {
List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();
//**默认什么也没做
configureHandlerExceptionResolvers(exceptionResolvers);
//**获取实际的异常处理器
//**按顺序创建ExceptionHandlerExceptionResolver,ResponseStatusExceptionResolver和DefaultHandlerExceptionResolver
if (exceptionResolvers.isEmpty()) {
addDefaultHandlerExceptionResolvers(exceptionResolvers);
}
extendHandlerExceptionResolvers(exceptionResolvers);
//**创建组合的异常处理器,并set实际的异常处理器
HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
composite.setOrder(0);
composite.setExceptionResolvers(exceptionResolvers);
return composite;
}
3.2.DispatcherServlet处理http请求
A.接收请求
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
...省略...
//**调用Controller
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
catch (Exception ex) { //**发生异常,赋值
dispatchException = ex;
}
...省略...
//**处理结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
B.处理结果
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
//**发生异常
if (exception != null) {
//**ModelAndViewDefiningException处理
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else { //**其它异常调用processHandlerException方法处理,返回null表示不能处理
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
...省略...
}
C.处理异常
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler, Exception ex) throws Exception {
//**调用所有的异常处理器处理异常,异常处理器返回不为null表示处理完毕
if (this.handlerExceptionResolvers != null) {
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
exMv = resolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
}
if (exMv != null) {
//**异常处理完毕,把异常存放到HttpServletRequest中
if (exMv.isEmpty()) {
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
}
...省略...
}
//**无法处理则抛出异常
throw ex;
}
4.全局异常处理器源码
4.1.HandlerExceptionResolver接口
提供了一个resolveException方法。处理异常,如果处理不了则返回null;
public interface HandlerExceptionResolver {
//**处理异常,如果处理不了返回null
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}
4.2.DefaultErrorAttributes异常处理器
把异常信息保存到HttpServletRequest和WebRequest中,并可以根据WebRequest获取异常信息;
public interface ErrorAttributes {
//**获取异常信息
Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace);
//**获取异常
Throwable getError(WebRequest webRequest);
}
public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver, Ordered {
//**把异常信息保存到HttpServletRequest中
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
storeErrorAttributes(request, ex);
return null;
}
private void storeErrorAttributes(HttpServletRequest request, Exception ex) {
request.setAttribute(ERROR_ATTRIBUTE, ex);
}
}
4.3.HandlerExceptionResolverComposite异常处理器
组合模式,组合实际的异常处理器。把异常按顺序交给其它异常处理器处理,直到能处理当前异常;
public class HandlerExceptionResolverComposite implements HandlerExceptionResolver, Ordered {
//**引用实际的异常处理器
private List<HandlerExceptionResolver> resolvers;
//**把异常按顺序交给其它异常处理器处理,直到能处理当前异常
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponseresponse, Object handler, Exception ex) {
if (this.resolvers != null) {
for (HandlerExceptionResolver handlerExceptionResolver : this.resolvers) {
ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (mav != null) {
return mav;
}
}
}
return null;
}
}
4.4.AbstractHandlerExceptionResolver异常处理器
对HandlerExceptionResolver接口进行扩展,支持设置支持的handler bean名称/class对象;
public abstract class AbstractHandlerExceptionResolver implements HandlerExceptionResolver, Ordered {
//**支持的handler bean名称,一般都是Controller
private Set<?> mappedHandlers;
//**支持的handler类对象,一般都是Controller
private Class<?>[] mappedHandlerClasses;
//**设置支持的handler bean名称和handler类对象
//**处理异常,判断是否支持当前的handler,如果支持则处理异常
public ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
if (shouldApplyTo(request, handler)) {
prepareResponse(ex, response);
ModelAndView result = doResolveException(request, response, handler, ex);
...
return result;
}
else {
return null;
}
}
//**判断是否支持当前的handler
protected boolean shouldApplyTo(HttpServletRequest request, @Nullable Object handler) {
if (handler != null) {
if (this.mappedHandlers != null && this.mappedHandlers.contains(handler)) {
return true;
}
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);
}
//**新的异常处理方法
protected abstract ModelAndView doResolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
}
4.5.SimpleMappingExceptionResolver异常处理器
实现自定义异常页面的功能。支持通过配置文件配置异常及返回的页面,可设置不支持的异常;
public class SimpleMappingExceptionResolver extends AbstractHandlerExceptionResolver {
//**配置的异常页面
private Properties exceptionMappings;
//**不支持的异常
private Class<?>[] excludedExceptions;
protected ModelAndView doResolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
//**获取当前异常的返回页面
String viewName = determineViewName(ex, request);
if (viewName != null) {
...
} else {
return null;
}
}
//**获取当前异常的页面,如果是不支持的异常,则直接返回null(处理失败)
protected String determineViewName(Exception ex, HttpServletRequest request) {
String viewName = null;
if (this.excludedExceptions != null) {
for (Class<?> excludedEx : this.excludedExceptions) {
if (excludedEx.equals(ex.getClass())) {
return null;
}
}
}
//**如果配置了异常页面,则查找当前异常的返回页面
if (this.exceptionMappings != null) {
viewName = findMatchingViewName(this.exceptionMappings, ex);
}
....
return viewName;
}
}
4.6.ResponseStatusExceptionResolver异常处理器
处理ResponseStatusException和@ResponseStatus标注的自定义异常,并且会递归查找上级异常;
public class ResponseStatusExceptionResolver extends AbstractHandlerExceptionResolver implements MessageSourceAware {
//**国际化
private MessageSource messageSource;
//**处理ResponseStatusException和@ResponseStatus标注的自定义异常
protected ModelAndView doResolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
try {
if (ex instanceof ResponseStatusException) { //**处理ResponseStatusException
return resolveResponseStatusException((ResponseStatusException) ex, request, response, handler);
}
//**处理@ResponseStatus标注的自定义异常
ResponseStatus status = AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class);
if (status != null) {
return resolveResponseStatus(status, request, response, handler, ex);
}
//**如果都不是则递归查找上级异常是否是ResponseStatusException和@ResponseStatus标注的自定义异常
if (ex.getCause() instanceof Exception) {
return doResolveException(request, response, handler, (Exception) ex.getCause());
}
}
...
return null;
}
}
4.7.DefaultHandlerExceptionResolver异常处理器
支持常见的异常处理;
public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
//**支持常见的异常
protected ModelAndView doResolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
try {
if (ex instanceof HttpRequestMethodNotSupportedException) {
return handleHttpRequestMethodNotSupported(
(HttpRequestMethodNotSupportedException) ex, request, response, handler);
}
else if (ex instanceof HttpMediaTypeNotSupportedException) {
return handleHttpMediaTypeNotSupported(
(HttpMediaTypeNotSupportedException) ex, request, response, handler);
}
else if (ex instanceof HttpMediaTypeNotAcceptableException) {
return handleHttpMediaTypeNotAcceptable(
(HttpMediaTypeNotAcceptableException) ex, request, response, handler);
}
else if (ex instanceof MissingPathVariableException) {
return handleMissingPathVariable(
(MissingPathVariableException) ex, request, response, handler);
}
else if (ex instanceof MissingServletRequestParameterException) {
return handleMissingServletRequestParameter(
(MissingServletRequestParameterException) ex, request, response, handler);
}
else if (ex instanceof ServletRequestBindingException) {
return handleServletRequestBindingException(
(ServletRequestBindingException) ex, request, response, handler);
}
else if (ex instanceof ConversionNotSupportedException) {
return handleConversionNotSupported(
(ConversionNotSupportedException) ex, request, response, handler);
}
else if (ex instanceof TypeMismatchException) {
return handleTypeMismatch(
(TypeMismatchException) ex, request, response, handler);
}
else if (ex instanceof HttpMessageNotReadableException) {
return handleHttpMessageNotReadable(
(HttpMessageNotReadableException) ex, request, response, handler);
}
else if (ex instanceof HttpMessageNotWritableException) {
return handleHttpMessageNotWritable(
(HttpMessageNotWritableException) ex, request, response, handler);
}
else if (ex instanceof MethodArgumentNotValidException) {
return handleMethodArgumentNotValidException(
(MethodArgumentNotValidException) ex, request, response, handler);
}
else if (ex instanceof MissingServletRequestPartException) {
return handleMissingServletRequestPartException(
(MissingServletRequestPartException) ex, request, response, handler);
}
else if (ex instanceof BindException) {
return handleBindException((BindException) ex, request, response, handler);
}
else if (ex instanceof NoHandlerFoundException) {
return handleNoHandlerFoundException(
(NoHandlerFoundException) ex, request, response, handler);
}
else if (ex instanceof AsyncRequestTimeoutException) {
return handleAsyncRequestTimeoutException(
(AsyncRequestTimeoutException) ex, request, response, handler);
}
}
..
return null;
}
}
4.8.AbstractHandlerMethodExceptionResolver异常处理器
处理HandlerMethod产生的异常,HandlerMethod是spring对bean中的方法的封装;
public abstract class AbstractHandlerMethodExceptionResolver extends AbstractHandlerExceptionResolver {
//**判断是否支持当前的handler,只支持HandlerMethod产生的异常
protected boolean shouldApplyTo(HttpServletRequest request, @Nullable Object handler) {
if (handler == null) {
return super.shouldApplyTo(request, null);
}
else if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
//**判断是否支持当前的handler所属的类
handler = handlerMethod.getBean();
return super.shouldApplyTo(request, handler);
}
else {
return false;
}
}
//**把父类的handler(Object)转换为handler(HandlerMethod)
protected final ModelAndView doResolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
return doResolveHandlerMethodException(request, response, (HandlerMethod) handler, ex);
}
//**转换后的异常处理方法
protected abstract ModelAndView doResolveHandlerMethodException(
HttpServletRequest request, HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception ex);
}
4.9.ExceptionHandlerExceptionResolver异常处理器
- 调用配置的异常处理方法处理异常,在异常处理方法可设置@RequestAttribute等参数(像Controller一样);
- 优先从handler当前类中查找异常处理方法。如果不存在,则从全局的ControllerAdvice类中查找异常处理方法;
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
implements ApplicationContextAware, InitializingBean {
//**参数处理器,处理配置的全局异常处理器中的参数(如@RequestAttribute标注的参数)
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
//**组合的参数处理器
private HandlerMethodArgumentResolverComposite argumentResolvers;
//**返回值处理器,处理配置的全局异常处理器中的返回值
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
//**组合的返回值处理器
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
//**存放类和它使用过的方法异常处理器
private final Map<Class<?>, ExceptionHandlerMethodResolver> exceptionHandlerCache = new ConcurrentHashMap<>(64);
//**存放配置的ControllerAdvice类和它支持方法异常处理器
private final Map<ControllerAdviceBean, ExceptionHandlerMethodResolver>exceptionHandlerAdviceCache = new LinkedHashMap<>();
@Override
public void afterPropertiesSet() {
//**初始化ControllerAdvice类
initExceptionHandlerAdviceCache();
//**获取参数处理器并组装为HandlerMethodArgumentResolverComposite
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
//**获取返回值处理器并组装为HandlerMethodReturnValueHandlerComposite
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
//**获取ControllerAdvice类,并创建对应的ExceptionHandlerMethodResolver
private void initExceptionHandlerAdviceCache() {
...
//**获取所有的ControllerAdvice类
List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
//**排序
AnnotationAwareOrderComparator.sort(adviceBeans);
for (ControllerAdviceBean adviceBean : adviceBeans) {
...
//**创建ExceptionHandlerMethodResolver并存放到exceptionHandlerAdviceCache中
ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);
if (resolver.hasExceptionMappings()) {
this.exceptionHandlerAdviceCache.put(adviceBean, resolver);
}
}
...
}
//**获取参数处理器(默认的参数处理器+配置的参数处理器)
protected List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
// Annotation-based argument resolution
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
return resolvers;
}
//**获取返回值处理器(默认的返回值处理器+配置的返回值处理器)
protected List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
// Single-purpose return value types
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(
getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));
// Annotation-based return value types
handlers.add(new ModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor(
getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));
// Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
// Catch-all
handlers.add(new ModelAttributeMethodProcessor(true));
return handlers;
}
//**处理异常
protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) {
//**获取方法调用处理器
ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
if (exceptionHandlerMethod == null) {
return null;
}
//**给方法调用处理器设置参数处理器
if (this.argumentResolvers != null) {
exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
//**给方法调用处理器设置返回值处理器
if (this.returnValueHandlers != null) {
exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
ServletWebRequest webRequest = new ServletWebRequest(request, response);
...
try {
Throwable cause = exception.getCause();
//**如果存在上级异常,则调用异常处理方法处理上级异常
if (cause != null) {
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, cause, handlerMethod);
}
else { //**调用异常处理方法处理当前异常
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, handlerMethod);
}
}
...
}
//**根据handler和异常获取方法调用处理器。先从handler的类中查找,在去ControllerAdvice类中查找
//**方法调用处理器负责调用配置的异常处理方法,包括解析@RequestAttribute等参数,处理返回结果
protected ServletInvocableHandlerMethod getExceptionHandlerMethod(
@Nullable HandlerMethod handlerMethod, Exception exception) {
Class<?> handlerType = null;
if (handlerMethod != null) {
//**从exceptionHandlerCache获取当前类使用过的处理器,如果没有则创建一个,并存放到exceptionHandlerCache中
handlerType = handlerMethod.getBeanType();
ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(handlerType);
if (resolver == null) {
resolver = new ExceptionHandlerMethodResolver(handlerType);
this.exceptionHandlerCache.put(handlerType, resolver);
}
//**从当前handler中查找配置的异常处理方法
Method method = resolver.resolveMethod(exception);
if (method != null) {
return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method);
}
if (Proxy.isProxyClass(handlerType)) {
handlerType = AopUtils.getTargetClass(handlerMethod.getBean());
}
}
//**从ControllerAdvice类中查找异常处理方法
for (Map.Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : this.exceptionHandlerAdviceCache.entrySet()) {
ControllerAdviceBean advice = entry.getKey();
if (advice.isApplicableToBeanType(handlerType)) {
ExceptionHandlerMethodResolver resolver = entry.getValue();
Method method = resolver.resolveMethod(exception);
if (method != null) {
return new ServletInvocableHandlerMethod(advice.resolveBean(), method);
}
}
}
return null;
}
}
4.10.ExceptionHandlerMethodResolver异常处理器
public class ExceptionHandlerMethodResolver {
//**过滤异常处理方法
public static final MethodFilter EXCEPTION_HANDLER_METHODS = method ->
AnnotatedElementUtils.hasAnnotation(method, ExceptionHandler.class);
//**存放类中所有的异常和处理方法
private final Map<Class<? extends Throwable>, Method> mappedMethods = new HashMap<>(16);
//**存放当前异常和异常处理方法
private final Map<Class<? extends Throwable>, Method> exceptionLookupCache = new ConcurrentReferenceHashMap<>(16);
//**查找类中的所有异常处理方法,并存放到mappedMethods中
public ExceptionHandlerMethodResolver(Class<?> handlerType) {
for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {
for (Class<? extends Throwable> exceptionType : detectExceptionMappings(method)) {
addExceptionMapping(exceptionType, method);
}
}
}
//**根据异常获取异常处理方法
public Method resolveMethod(Exception exception) {
return resolveMethodByThrowable(exception);
}
//**根据异常获取异常处理方法(会递归查找上级异常)
public Method resolveMethodByThrowable(Throwable exception) {
Method method = resolveMethodByExceptionType(exception.getClass());
if (method == null) {
Throwable cause = exception.getCause();
if (cause != null) {
method = resolveMethodByExceptionType(cause.getClass());
}
}
return method;
}
//**根据异常的class对象获取异常处理方法(先从exceptionLookupCache中查找,如果不存在则计算,然后保存在exceptionLookupCache中)
public Method resolveMethodByExceptionType(Class<? extends Throwable> exceptionType) {
Method method = this.exceptionLookupCache.get(exceptionType);
if (method == null) {
method = getMappedMethod(exceptionType);
this.exceptionLookupCache.put(exceptionType, method);
}
return method;
}
//**从mappedException中查找异常处理方法,并获取优先度最高的一个
private Method getMappedMethod(Class<? extends Throwable> exceptionType) {
List<Class<? extends Throwable>> matches = new ArrayList<>();
for (Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) {
if (mappedException.isAssignableFrom(exceptionType)) {
matches.add(mappedException);
}
}
if (!matches.isEmpty()) {
matches.sort(new ExceptionDepthComparator(exceptionType));
return this.mappedMethods.get(matches.get(0));
}
else {
return null;
}
}
}