如何做阿语垂直网站,巩义网站优化公司,做网站怎么切图,wordpress 推广 插件https://www.bilibili.com/video/BV1sS411c7Mo 文章目录 一、全局异常处理器的类型1-1、实现方式一1-2、实现方式二 二、全局异常拦截点2-1、入口2-2、全局异常拦截器是如何注入到 DispatcherServlet 的 三、ControllerAdvice 如何解析、执行3-1、解析3-2、执行 四、其它4-1、设…https://www.bilibili.com/video/BV1sS411c7Mo 文章目录 一、全局异常处理器的类型1-1、实现方式一1-2、实现方式二 二、全局异常拦截点2-1、入口2-2、全局异常拦截器是如何注入到 DispatcherServlet 的 三、ControllerAdvice 如何解析、执行3-1、解析3-2、执行 四、其它4-1、设置HTTP状态码4-2、异常处理器排序4-3、所谓全局异常 最近在做系统升级的时候引发了一个BUG原本系统是有一个异常处理器A引入了某个底包中也带了一个异常处理器B最终走了底包的异常处理器B。 A对于异常的时候会返回HTTP状态码为500B对于异常处理器返回的HTTP状态码为200前端基于HTTP状态码进行提示的就出了问题
本篇文章我们就来讨论一下在JavaWeb中的全局异常处理器是何时何地如何执行的。
在进行学习之前需要先知道HTTP执行流程SpringMVC执行流程 一、全局异常处理器的类型 全局异常处理器的父接口是 HandlerExceptionResolver简单来说就是实现或间接实现它的类就叫全局异常处理器。
package org.springframework.web.servlet;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;public interface HandlerExceptionResolver {NullableModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Nullable Object handler, Exception ex);
}HandlerExceptionResolver 的继承关系图 1-1、实现方式一 SpringBoot项目最大的特点就是注解在SpringBoot项目中全局异常拦截的注解是ControllerAdvice RestControllerAdvice ControllerAdvice ResponseBody 使用 ControllerAdvice的类最终会生成 ExceptionHandlerExceptionResolver 1-2、实现方式二 重写 doResolveHandlerMethodException 方法然后注册当前的bean
public class ExceptionHandler extends AbstractHandlerMethodExceptionResolver {private final static Logger logger LoggerFactory.getLogger(ExceptionHandler.class);Overrideprotected ModelAndView doResolveHandlerMethodException(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod, Exception ex) {return new ModelAndView();}
}二、全局异常拦截点 2-1、入口 org.springframework.web.servlet.DispatcherServlet#doDispatch 这个方法就是SpringMVC的执行流程的核心代码了下面是简化代码
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest request;HandlerExecutionChain mappedHandler null;boolean multipartRequestParsed false;WebAsyncManager asyncManager WebAsyncUtils.getAsyncManager(request);try {ModelAndView mv null;Exception dispatchException null;try {// ...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) {// ....}catch (Throwable err) {// ....}finally {// ... }
}org.springframework.web.servlet.DispatcherServlet#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) {Object handler (mappedHandler ! null ? mappedHandler.getHandler() : null);// 异常处理mv processHandlerException(request, response, handler, exception);errorView (mv ! null);}// ...
}org.springframework.web.servlet.DispatcherServlet#processHandlerException
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,Nullable Object handler, Exception ex) throws Exception {// Success and error responses may use different content typesrequest.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);// Check registered HandlerExceptionResolvers...ModelAndView exMv null;if (this.handlerExceptionResolvers ! null) {// 遍历循环所有的拦截器来尝试处理这个异常拦截器已经按照 order 排好序了for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {exMv resolver.resolveException(request, response, handler, ex);// 只有返回了 ModelAndView 才结束不然一直往下走if (exMv ! null) {break;}}}// ...// 如果没有全局异常处理器 可以处理这个异常 就继续抛出去throw ex;
}2-2、全局异常拦截器是如何注入到 DispatcherServlet 的 上面看到是从 handlerExceptionResolvers 从获取所有的异常处理器它是一个list
Nullable
private ListHandlerExceptionResolver handlerExceptionResolvers;在DispatcherServlet里面有一个onRefresh方法它是重写的父类FrameworkServlet的在初始化ServletBean的时候会被调用一次它里面会做很多初始化的操作其中一个就是获取容器里面的全局异常拦截器 一层层看上去其实是 Servlet接口的 init方法触发的
Override
protected void onRefresh(ApplicationContext context) {initStrategies(context);
}protected void initStrategies(ApplicationContext context) {// ...initHandlerExceptionResolvers(context);// ...
}找到bean容器里面的所有异常拦截器把它存在 handlerExceptionResolvers 里面并排序 private void initHandlerExceptionResolvers(ApplicationContext context) {this.handlerExceptionResolvers null;if (this.detectAllHandlerExceptionResolvers) {// 从bean容器里面找到所有的 HandlerExceptionResolverMapString, HandlerExceptionResolver matchingBeans BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerExceptionResolvers new ArrayList(matchingBeans.values());// 排序AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);}}// ...
}三、ControllerAdvice 如何解析、执行 3-1、解析 在springframework 中有这样一个类 ExceptionHandlerExceptionResolver
package org.springframework.web.servlet.mvc.method.annotation;public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolverimplements ApplicationContextAware, InitializingBean {// ...
}⚠️可以回到【全局异常处理器的类型】的图看看ExceptionHandlerExceptionResolver其实就是全局异常处理器HandlerExceptionResolver的子类 它实现了 InitializingBean重写了afterPropertiesSet这个方法会在bean初始化完之后执行
Override
public void afterPropertiesSet() {// Do this first, it may add ResponseBodyAdvice beansinitExceptionHandlerAdviceCache();// ...
}initExceptionHandlerAdviceCache 会把所有使用了ControllerAdvice 的bean找到并把它存在自己的参数里面
private final MapControllerAdviceBean, ExceptionHandlerMethodResolver exceptionHandlerAdviceCache new LinkedHashMap();private void initExceptionHandlerAdviceCache() {if (getApplicationContext() null) {return;}// 找到所有使用了 ControllerAdvice 的beanListControllerAdviceBean adviceBeans ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());for (ControllerAdviceBean adviceBean : adviceBeans) {Class? beanType adviceBean.getBeanType();if (beanType null) {throw new IllegalStateException(Unresolvable type for ControllerAdviceBean: adviceBean);}// 解析全部的 ExceptionHandler 注解ExceptionHandlerMethodResolver resolver new ExceptionHandlerMethodResolver(beanType);if (resolver.hasExceptionMappings()) {// 存入当前的类参数里面this.exceptionHandlerAdviceCache.put(adviceBean, resolver);}if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {this.responseBodyAdvice.add(adviceBean);}}// ...
}org.springframework.web.method.ControllerAdviceBean#findAnnotatedBeans
public static ListControllerAdviceBean findAnnotatedBeans(ApplicationContext context) {ListableBeanFactory beanFactory context;if (context instanceof ConfigurableApplicationContext) {// Use internal BeanFactory for potential downcast to ConfigurableBeanFactory abovebeanFactory ((ConfigurableApplicationContext) context).getBeanFactory();}ListControllerAdviceBean adviceBeans new ArrayList();// 遍历所有的beanfor (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Object.class)) {if (!ScopedProxyUtils.isScopedTarget(name)) {// 找到符合的beanControllerAdvice controllerAdvice beanFactory.findAnnotationOnBean(name, ControllerAdvice.class);if (controllerAdvice ! null) {// 存起来adviceBeans.add(new ControllerAdviceBean(name, beanFactory, controllerAdvice));}}}// 排序OrderComparator.sort(adviceBeans);return adviceBeans;
}配合ControllerAdvice 注解的通常是 ExceptionHandler 它用来制定具体的异常把所有的 ExceptionHandler都存入了 mappedMethods 中org.springframework.web.method.annotation.ExceptionHandlerMethodResolver#ExceptionHandlerMethodResolver
public ExceptionHandlerMethodResolver(Class? handlerType) {for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {for (Class? extends Throwable exceptionType : detectExceptionMappings(method)) {addExceptionMapping(exceptionType, method);}}
}
private void addExceptionMapping(Class? extends Throwable exceptionType, Method method) {Method oldMethod this.mappedMethods.put(exceptionType, method);if (oldMethod ! null !oldMethod.equals(method)) {throw new IllegalStateException(Ambiguous ExceptionHandler method mapped for [ exceptionType ]: { oldMethod , method });}
}至此ControllerAdvice的解析完成
生成了一个ExceptionHandlerExceptionResolver它通过多级实现了 HandlerExceptionResolver所有使用ControllerAdvice的类都存在了 exceptionHandlerAdviceCache 中所有使用 ExceptionHandler 的方法否存在了mappedMethods 中 3-2、执行 从【2-1】得知执行异常处理器的时候是执行 HandlerExceptionResolver.resolveException方法它只有这一个方法从【3-1】得知所有使用 ControllerAdvice 注解的类都被存在了ExceptionHandlerExceptionResolver 中从【1】得知ExceptionHandlerExceptionResolver的继承关系如下图 一层层去看调用关系最终会执行的是 这个很简单直接去看即可org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#doResolveHandlerMethodException
执行过程就是循环exceptionHandlerAdviceCache中的每一个全局拦截器再循环每个拦截器里面的mappedMethods看哪个可以匹配上就执行哪个 四、其它 4-1、设置HTTP状态码 大多数情况下我们会自定义返回值code比如未鉴权返回给前端HTTP状态码是200code为401但在某些情况下也会直接返回HTTP状态码401可以使用 ResponseStatus
ResponseStatus(HttpStatus.UNAUTHORIZED)
ExceptionHandler(Exception.class)
public ResultObj bizExceptionHandler(Exception e) {log.info(全局异常拦截, e);return ResultObj.success();
}4-2、异常处理器排序 springframework 里面提供了一个Ordered 接口实现它重写里面 getOrder 方法就可以进行排序了 4-3、所谓全局异常
并不是系统任何异常都会被它所拦截因为我们已经知道它的执行点是在MVC的流程中所以就只有HTTP异常才会被拦截处理 文章转载自: http://www.morning.djmdk.cn.gov.cn.djmdk.cn http://www.morning.mfnsn.cn.gov.cn.mfnsn.cn http://www.morning.wftrs.cn.gov.cn.wftrs.cn http://www.morning.grpbt.cn.gov.cn.grpbt.cn http://www.morning.bybhj.cn.gov.cn.bybhj.cn http://www.morning.gzgwn.cn.gov.cn.gzgwn.cn http://www.morning.hcxhz.cn.gov.cn.hcxhz.cn http://www.morning.ffhlh.cn.gov.cn.ffhlh.cn http://www.morning.mfxcg.cn.gov.cn.mfxcg.cn http://www.morning.lksgz.cn.gov.cn.lksgz.cn http://www.morning.jiuyungps.com.gov.cn.jiuyungps.com http://www.morning.nndbz.cn.gov.cn.nndbz.cn http://www.morning.dnqpq.cn.gov.cn.dnqpq.cn http://www.morning.lgwpm.cn.gov.cn.lgwpm.cn http://www.morning.jyknk.cn.gov.cn.jyknk.cn http://www.morning.ksbmx.cn.gov.cn.ksbmx.cn http://www.morning.hbpjb.cn.gov.cn.hbpjb.cn http://www.morning.jwdys.cn.gov.cn.jwdys.cn http://www.morning.gbrps.cn.gov.cn.gbrps.cn http://www.morning.fblkr.cn.gov.cn.fblkr.cn http://www.morning.hgsylxs.com.gov.cn.hgsylxs.com http://www.morning.frmmp.cn.gov.cn.frmmp.cn http://www.morning.zmlbq.cn.gov.cn.zmlbq.cn http://www.morning.qkxt.cn.gov.cn.qkxt.cn http://www.morning.xfwnk.cn.gov.cn.xfwnk.cn http://www.morning.knwry.cn.gov.cn.knwry.cn http://www.morning.zglrl.cn.gov.cn.zglrl.cn http://www.morning.bgrsr.cn.gov.cn.bgrsr.cn http://www.morning.yqrfn.cn.gov.cn.yqrfn.cn http://www.morning.ubpsa.cn.gov.cn.ubpsa.cn http://www.morning.myfwb.cn.gov.cn.myfwb.cn http://www.morning.rhjhy.cn.gov.cn.rhjhy.cn http://www.morning.rjrz.cn.gov.cn.rjrz.cn http://www.morning.rhpgk.cn.gov.cn.rhpgk.cn http://www.morning.qfmns.cn.gov.cn.qfmns.cn http://www.morning.kqgqy.cn.gov.cn.kqgqy.cn http://www.morning.rnfn.cn.gov.cn.rnfn.cn http://www.morning.fnfxp.cn.gov.cn.fnfxp.cn http://www.morning.csznh.cn.gov.cn.csznh.cn http://www.morning.kqlrl.cn.gov.cn.kqlrl.cn http://www.morning.zrdhd.cn.gov.cn.zrdhd.cn http://www.morning.rkrcd.cn.gov.cn.rkrcd.cn http://www.morning.kwxr.cn.gov.cn.kwxr.cn http://www.morning.tpqzs.cn.gov.cn.tpqzs.cn http://www.morning.rwmqp.cn.gov.cn.rwmqp.cn http://www.morning.lwzpp.cn.gov.cn.lwzpp.cn http://www.morning.ftzll.cn.gov.cn.ftzll.cn http://www.morning.mhpkz.cn.gov.cn.mhpkz.cn http://www.morning.pyxtn.cn.gov.cn.pyxtn.cn http://www.morning.xnwjt.cn.gov.cn.xnwjt.cn http://www.morning.smxrx.cn.gov.cn.smxrx.cn http://www.morning.ftdlg.cn.gov.cn.ftdlg.cn http://www.morning.hlzpb.cn.gov.cn.hlzpb.cn http://www.morning.guanszz.com.gov.cn.guanszz.com http://www.morning.qsswb.cn.gov.cn.qsswb.cn http://www.morning.wqbrg.cn.gov.cn.wqbrg.cn http://www.morning.zmzdx.cn.gov.cn.zmzdx.cn http://www.morning.pqjpw.cn.gov.cn.pqjpw.cn http://www.morning.kaylyea.com.gov.cn.kaylyea.com http://www.morning.kcypc.cn.gov.cn.kcypc.cn http://www.morning.c7491.cn.gov.cn.c7491.cn http://www.morning.xpqsk.cn.gov.cn.xpqsk.cn http://www.morning.cwqln.cn.gov.cn.cwqln.cn http://www.morning.mlwpr.cn.gov.cn.mlwpr.cn http://www.morning.ghkgl.cn.gov.cn.ghkgl.cn http://www.morning.spwm.cn.gov.cn.spwm.cn http://www.morning.fjlsfs.com.gov.cn.fjlsfs.com http://www.morning.nbdtdjk.cn.gov.cn.nbdtdjk.cn http://www.morning.lynkz.cn.gov.cn.lynkz.cn http://www.morning.c7495.cn.gov.cn.c7495.cn http://www.morning.kjkml.cn.gov.cn.kjkml.cn http://www.morning.hpnhl.cn.gov.cn.hpnhl.cn http://www.morning.nzmw.cn.gov.cn.nzmw.cn http://www.morning.bojkosvit.com.gov.cn.bojkosvit.com http://www.morning.snmth.cn.gov.cn.snmth.cn http://www.morning.rnht.cn.gov.cn.rnht.cn http://www.morning.ygflz.cn.gov.cn.ygflz.cn http://www.morning.crxdn.cn.gov.cn.crxdn.cn http://www.morning.3jiax.cn.gov.cn.3jiax.cn http://www.morning.cwfkm.cn.gov.cn.cwfkm.cn