范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

源码角度深度解析Spring的异常处理ExceptionHandler的实现原理

  ExceptionHandler的作用
  ExceptionHandler是Spring框架提供的一个注解,用于处理应用程序中的异常。当应用程序中发生异常时,ExceptionHandler将优先地拦截异常并处理它,然后将处理结果返回到前端。该注解可用于类级别和方法级别,以捕获不同级别的异常。
  在Spring中使用ExceptionHandler非常简单,只需在需要捕获异常的方法上注解@ExceptionHandler,然后定义一个方法,该方法将接收异常并返回异常信息,并将该异常信息展示给前端用户。ExceptionHandler的使用
  说明:针对可能出问题的Controller,新增注解方法@ExceptionHandler,下面是一个基本的ExceptionHandler示例:@RestController public class ExceptionController { 	     @ExceptionHandler(Exception.class)     public ResponseEntity handleException(Exception ex) {         return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)                 .body("An error occurred: " + ex.getMessage());     }     @RequestMapping("/test")     public String test() throws Exception {         throw new Exception("Test exception!");     } } 复制代码
  在上面的示例中,我们定义了一个叫做ExceptionController的类,该类是一个**@RestController**注解的控制器,它包括一个可以产生异常的请求处理程序,一个用于捕获和处理异常的@ExceptionHandler方法。
  @RequestMapping注解配置了一个名为"/test"的API,该API将抛出一个异常,该异常将由我们上面的ExceptionHandler进行处理。当请求"/test"时,Controller方法将引发异常并触发@ExceptionHandler方法。
  在上面的@ExceptionHandler方法中,我们通过ResponseEntity将异常信息提供给客户端,HTTP状态码设置为500。这使客户端了解已发生错误,并能够在日志中记录异常信息以便日后调试。
  总之,使用ExceptionHandler能够更好的掌控应用的异常信息,使得应用在发生异常的时候更加可控,并且更加容易进行调试。ExceptionHandler的注意事项Controller类下多个**@ExceptionHandler**上的异常类型不能出现一样的,否则运行时抛异常。@ExceptionHandler下方法返回值类型支持多种,常见的ModelAndView,@ResponseBody注解标注,ResponseEntity等类型都OK.源码分析介绍原理说明-doDispatch
  代码片段位于:org.springframework.web.servlet.DispatcherServlet#doDispatch
  执行**@RequestMapping方法抛出异常后,Spring框架 try-catch的方法捕获异常, 正常逻辑发不发生异常都会走processDispatchResult**流程 ,区别在于异常的参数是否为null .	HandlerExecutionChain mappedHandler = null; 	Exception dispatchException = null; 	ModelAndView mv = null;     try{         //根据请求查找handlerMapping找到controller         mappedHandler=getHandler(request);          //找到处理器适配器HandlerAdapter         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());          if(!mappedHandler.applyPreHandle(request,response)){              //拦截器preHandle             return ;         }               //调用处理器适配器执行@RequestMapping方法         mv=ha.handle(request,response);          //拦截器postHandle         mappedHandler.applyPostHandle(request,response,mv);       }catch(Exception ex){         dispatchException=ex;     }     //将异常信息传入了     processDispatchResult(request,response,mappedHandler,mv,dispatchException)  复制代码原理说明-processDispatchResult
  代码片段位于:org.springframework.web.servlet.DispatcherServlet#processDispatchResult
  如果 @RequestMapping 方法抛出异常,拦截器的postHandle方法不执行,进入processDispatchResult,判断入参dispatchException,不为null , 代表发生异常,调用processHandlerException处理。原理说明-processHandlerException
  代码片段位于:org.springframework.web.servlet.DispatcherServlet#processHandlerException
  this当前对象指dispatchServlet,handlerExceptionResolvers可以看到三个HandlerExceptionResolver,这三个是Spring框架帮我们注册的,遍历有序集合handlerExceptionResolvers,调用接口的resolveException方法。
  注册的第一个HandlerExceptionResolver.ExceptionHandlerExceptionResolver, 继承关系如下面所示。
  原理说明-AbstractHandlerExceptionResolver
  代码片段位于:org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver#resolveException
  这里AbstractHandlerExceptionResolver的shouldApplyTo都返回true, logException用来记录日志、prepareResponse方法,用来设置response的Cache-Control。
  异常处理方法就位于doResolveException
  注意:AbstractHandlerExceptionResolver和AbstractHandlerMethodExceptionResolver名字看起来非常相似,但是作用不同,一个是面向整个类的,一个是面向方法级别的。原理说明-AbstractHandlerMethodExceptionResolver
  代码片段位于:org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver#shouldApplyTo
  接口方法实现AbstractHandlerExceptionResolver的resolveException,先判断shouldApplyTo,AbstractHandlerExceptionResolver 和子类AbstractHandlerMethodExceptionResolver都实现了shouldApplyTo方法,子类的shouldApplyTo都调用父类AbstractHandlerExceptionResolver的shouldApplyTo.父类AbstractHandlerExceptionResolver的shouldApplyTo方法.
  代码片段位于:org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver#shouldApplyTo
  Spring初始化的时候并没有额外配置 , 所以mappedHandlers和mappedHandlerClasses都为null, 可以在这块扩展进行筛选 ,AbstractHandlerExceptionResolver提供了setMappedHandlerClasses 、setMappedHandlers用于扩展。doResolveException
  代码片段位于:org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver#doResolveException Spring请求方法执行一样的处理方式,设置argumentResolvers、returnValueHandlers,之后进行调用异常处理方法。获取@ExceptionHandler
  @ExceptionHandler的方法入参支持:Exception ;SessionAttribute 、 RequestAttribute注解、 HttpServletRequest 、HttpServletResponse、HttpSession。
  @ExceptionHandler方法返回值常见的可以是: ModelAndView 、@ResponseBody注解、ResponseEntity。getExceptionHandlerMethod方法
  getExceptionHandlerMethod说明: 获取对应的@ExceptionHandler方法,封装成ServletInvocableHandlerMethod返回。
  exceptionHandlerCache是针对Controller层面的@ExceptionHandler的处理方式,而exceptionHandlerAdviceCache是针对@ControllerAdvice的处理方式. 这两个属性都位于ExceptionHandlerExceptionResolver中。
  ExceptionHandlerMethodResolver,缓存A之前没存储过Controller的class ,所以新建一个ExceptionHandlerMethodResolver 加入缓存中,ExceptionHandlerMethodResolver 的初始化工作一定做了某些工作。
  resolveMethod方法
  根据异常对象让 ExceptionHandlerMethodResolver 解析得到 method , 匹配到异常处理方法就直接封装成对象 ServletInvocableHandlerMethod ; 就不会再去走@ControllerAdvice里的异常处理器了,这里说明了。
  resolveMethodByExceptionType根据当前抛出异常寻找 匹配的方法,并且做了缓存,以后遇到同样的异常可以直接走缓存取出
  resolveMethodByExceptionType方法,尝试从缓存A:exceptionLookupCache中根据异常class类型获取Method ,初始时候肯定缓存为空 ,就去遍历ExceptionHandlerMethodResolver的mappedMethods(上面提及了key为异常类型,value为method,exceptionType为当前@RequestMapping方法抛出的异常,判断当前异常类型是不是@ExceptionHandler中value声明的子类或本身,满足条件就代表匹配上了;
  可能存在多个匹配的方法,使用ExceptionDepthComparator排序,排序规则是按照继承顺序来(继承关系越靠近数值越小,当前类最小为0,顶级父类Throwable为int最大值),排序之后选取继承关系最靠近的那个,并且ExceptionHandlerMethodResolver的exceptionLookupCache中,key为当前抛出的异常,value为解析出来的匹配method.全局级别异常处理器实现HandlerExceptionResolver接口public class MyHandlerExceptionResolver implements HandlerExceptionResolver {      @Override      public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {         ModelMap mmp=new ModelMap();         mmp.addAttribute("ex",ex.getMessage());         return new ModelAndView("error",mmp);     } } 复制代码使用方式: 只需要将该Bean加入到Spring容器,可以通过Xml配置,也可以通过注解方式加入容器;
  方法返回值不为null才有意义,如果方法返回值为null,可能异常就没有被捕获.缺点分析:比如这种方式全局异常处理返回JSP、velocity等视图比较方便,返回json或者xml等格式的响应就需要自己实现了.如下是我实现的发生全局异常返回JSON的简单例子.public class MyHandlerExceptionResolver implements HandlerExceptionResolver {     @Override     public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {         System.out.println("发生全局异常!");         ModelMap mmp=new ModelMap();         mmp.addAttribute("ex",ex.getMessage());         response.addHeader("Content-Type","application/json;charset=UTF-8");         try {             new ObjectMapper().writeValue(response.getWriter(),ex.getMessage());             response.getWriter().flush();         } catch (IOException e) {             e.printStackTrace();         }         return new ModelAndView();     } } 复制代码全局级别异常处理器@ControllerAdvice+@ExceptionHandler使用方法
  用法说明:这种情况下 @ExceptionHandler与第一种方式用法相同,返回值支持ModelAndView,@ResponseBody等多种形式。@ControllerAdvice public class GlobalController {     @ExceptionHandler(RuntimeException.class)     public ModelAndView fix1(Exception e){         System.out.println("全局的异常处理器");         ModelMap mmp=new ModelMap();         mmp.addAttribute("ex",e);         return new ModelAndView("error",mmp);     } } 复制代码方式一:提到ExceptionHandlerExceptionResolver不仅维护@Controller级别的@ExceptionHandler,同时还维护的@ControllerAdvice级别的@ExceptionHandler代码片段位于: isApplicableToBeanType方法是用来做条件判断的,@ControllerAdvice注解有很多属性用来设置条件, basePackageClasses、assignableTypes、annotations等,比如我限定了annotations为注解X, 那标注了@X 的ControllerA就可以走这个异常处理器,ControllerB就不能走这个异常处理器。
  现在问题的关键就只剩下了exceptionHandlerAdviceCache是什么时候扫描@ControllerAdvice的,下面的逻辑和@ExceptionHandler的逻辑一样了,exceptionHandlerAdviceCache初始化逻辑:
  代码片段位于:org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#afterPropertiesSet,afterPropertiesSet是Spring bean创建过程中一个重要环节。
  代码片段位于:org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#initExceptionHandlerAdviceCache
  ControllerAdviceBean.findAnnotatedBeans方法查找了SpringMvc父子容器中标注 @ControllerAdvice 的bean, new ExceptionHandlerMethodResolver初始化时候解析了当前的@ControllerAdvice的bean的@ExceptionHandler,加入到ExceptionHandlerExceptionResolver的exceptionHandlerAdviceCache中,key为ControllerAdviceBean,value为ExceptionHandlerMethodResolver . 到这里exceptionHandlerAdviceCache就初始化完毕。Spring父子容器中所有@ControllerApce的bean的方法
  代码片段位于:org.springframework.web.method.ControllerAdviceBean#findAnnotatedBeans
  遍历了SpringMVC父子容器中所有的bean,标注ControllerAdvice注解的bean加入集合返回。比较说明
  @Controller+@ExceptionHandler、HandlerExceptionResolver接口形式、@ControllerAdvice+@ExceptionHandler优缺点说明:调用优先级@Controller+@ExceptionHandler优先级最高@ControllerAdvice+@ExceptionHandler 略低HandlerExceptionResolver最低。
  三种方式并存的情况 优先级越高的越先选择,而且被一个捕获处理了就不去执行其他的。三种方式都支持多种返回类型@Controller+@ExceptionHandler、@ControllerAdvice+@ExceptionHandler可以使用Spring支持的@ResponseBody、ResponseEntity。HandlerExceptionResolver方法声明返回值类型只能是 ModelAndView,如果需要返回JSON、xml等需要自己实现.。缓存利用@Controller+@ExceptionHandler的缓存信息在ExceptionHandlerExceptionResolver的exceptionHandlerCache,@ControllerAdvice+@ExceptionHandler的缓存信息在ExceptionHandlerExceptionResolver的exceptionHandlerAdviceCache中,HandlerExceptionResolver接口是不做缓存的,在异常报错的情况下才会走自己的HandlerExceptionResolver实现类,多少有点性能损耗.

比亚迪能给南宁带来多少工业产值,能让南宁摆脱工业发展困局吗?比亚迪落户南宁,使得很多南宁人兴奋不已,纷纷认为南宁工业即将迎来大发展,南宁工业有救了,南宁工业即将赶上柳州,南宁终于有大企业了等等。那么,现实有那么乐观吗?我们来做个分析。过去二32页2023年移动电商应用市场洞察关注公众号星夜大数据获取完整版报告摘要全球移动电商应用下载量持续增长。2022年全球移动电商应用下载量为59亿次,相对2021年增长7。1。其中65的移动电商应用下载量来自Goog市场日报大象起舞,三桶油集体狂飙!卤味巨头大跳水,逼近跌停!今日,A股三大指数集体低开,沪指低开0。05,深成指低开0。16,创业板指低开0。35。三桶油开盘集体拉升,中国石化大涨超5,股价创4年多以来新高,总市值为6438亿元,中国海油盘宋清辉新型消费孕育巨大投资机会备受市场关注经济学家宋清辉赞同全国人大代表盐津铺子食品股份有限公司董事长张学武的观点。他认为,新型消费本质上是消费者对于商品或服务的要求越来越高,更倾向于追求个性化多样化和高品质。宋清辉分析,CBA直播福建男篮VS新疆男篮比赛时间2023年3月8日1935CBA直播福建男篮VS新疆男篮观赛入口https857zb6。cc?fromanlan9(长按链接后点击搜索直达直播页面)新疆男篮曾荣获CBA冠军价格战新能源双重挤压,两个细分市场或面临崩盘洗牌进入2023年以来,中国车市以一种令人震惊的方式开始了第一季度的冲击,从传统燃油车到新能源车,从边缘化品牌到主流大厂,从局部区域到波及全国,价格战来得凶猛异常。惨烈的价格战代表了汽复通首月罗湖口岸超310万人次出入境,单日破15万自2月6日罗湖口岸全面恢复通关以来,出入境旅客不断攀升。复通首月,深圳出入境边防检查总站罗湖边检站查验出入境人员超310万人次,约占深圳地区口岸出入境客流量33,其中3月4日出入境流量卡这么便宜,套路都有哪些?本内容来源于什么值得买APP,观点仅代表作者本人作者lzcer有没有套路?答案是肯定的有!都有哪些套路?首先是运营商的套路套餐组成一定是由基础套餐额外赠送(订购)内容组成,目前比较全面恢复通关满月,解锁深圳湾口岸通关新图景来源读特6。6万6。8万7万这是自2月6日深港陆路口岸全面正常通关后,深圳湾口岸单日最高出入境客流量的变化。节节攀升的数字背后,是一位位通关旅客步履匆匆的身影,是一份份思乡心切的想穿国货丢脸?这10个在国外很火的中国服装品牌,你应该感到自豪!虽然近年来国货有了回潮的趋势,但是在横扫一遍大街上的人,穿国货的还是少之又少,似乎穿国货丢脸的刻板心理依旧没有改变。你不穿,不代表它不好!这10个在国外火到爆的中国服装品牌,横扫海看了U20亚洲杯,才明白谁在真正为中国足球谋出路?U20亚洲杯正在如火如荼地进行,国青目前2战积3分,把出线的主动权掌握在自己手中,只要最后一场拿下吉尔吉斯斯坦,就能够晋级到下一轮。看了U20亚洲杯,说球君才明白谁在真正为中国足球
OPPO电视不用U盘如何安装电视家3。0?方法一1打开oppo电视,在顶部导航栏中找到应用栏底下的应用搜索2在应用搜索中输入dsj,找到大世界软件下载并打开3打开大世界,按遥控器6次下键,可以看到电视上显示提醒安装电视家,春天穿衬衫就是这么好看,多款衬衫穿搭案例,怎么穿都好看春装的穿搭总是十分丰富,不同的元素诠释出不同的面貌与风采。如果怎么搭让你选择困难不如直接穿上最简单的衬衫。很多女生在初春的季节,穿搭总是想要利用一些个性化的单品来呈现出与众不同的新波尔津吉斯首秀25分库兹马238奇才擒步行者NBA常规赛3月7日继续进行,本场比赛波尔津吉斯上演奇才生涯首秀。最终,奇才以133123战胜步行者。首节开始,波尔津吉斯上来就独得6分帮助奇才92开局!步行者迅速回敬一波82迫近张帅4年半后再夺女单冠军仅次李娜郑洁现役第一北京时间3月7日凌晨,在2022赛季女子网球WTA250里昂站决赛中,张帅21逆转战胜乌克兰选手亚斯特列慕斯卡,时隔四年半再夺WTA巡回赛女单冠军,生涯首个室内赛冠军,生涯第三个巡茶马古道的由来一个因茶马互市而闻名的特殊地域,一条最壮观的文化旅游路线,一段最奇妙的历史之旅,贯穿川藏滇藏和青藏三条大道的交通网络茶马古道,绝对算得上人类遗留的财富,文化的结晶。茶马古道,大约起坐者的福音!揉一揉,缓解颈项腰腿疼痛它是坐者的福音!揉一揉,缓解颈项腰腿疼痛缓解颈项腰背痛,后溪效果好。后溪穴为手太阳小肠经腧穴,刺激后溪穴,则是利用其火与木的特性,通督脉,振阳气。像我们平时坐着上班学习的时候,就可媲美武功山,还是世界佛教名山,户外人必去的朝圣之路来了我的人生也许与你的大相径庭但它是我自己做出的选择生活不是选出来的,是过出来的电影朝圣之路图片电影朝圣之路这是一部电影中的经典话句也是每一位朝圣者户外徒步者的内心独白这部电影就是TH大寨风彩依旧大寨村时值今日,大寨在全国农村依旧领先,全国闻名,大寨之花依然璀璨,共同富裕领先一步,大寨人精神面貌焕然一新。大寨经济大寨从单纯农业经济走向了农工商一体化发展的路子。到2010年底山西房地产老板,投资5亿在河南打造景区,风景优美吸引市民观光近几年来,随着我国经济水平的不断提升,很多朋友都会在自己休闲放假之余,外出旅游散心,因此我国的旅游业也得到了前所未有的发展。然而,随着旅游业的逐步发展,从而吸引了很多投资者的目光,正式官宣!国家队5人教练人才库出炉,杨鸣领衔,巩晓彬李楠落选目前CBA联赛激战正酣,排在前四位的分别是辽宁男篮上海男篮浙江广厦以及浙江稠州男篮,这四支球队辽篮先赛一场以26胜5负领先其他球队一个胜场。而卫冕冠军广东宏远男篮深圳男篮广州以及北跟杨幂逛街,baby为她庆生,欧阳娜娜是她闺蜜,宋祖儿太社牛了最近,有狗仔拍到杨幂宋祖儿杨芸晴在某公园游玩的画面,这三位的同框让不少网友觉得有点次元壁被打破的既视感,画面中几位穿着冬装,一会玩脚踏车,一会打篮球,还去抓了娃娃,气氛融洽,看起来