当前位置:首页 > 公众号精选 > 架构师社区
[导读]何为全局异常的自适应呢?

SpringBoot自适应异常处理

SpringBoot自适应异常处理

效果演示

我们先来看一下Springboot的默认效果

浏览器访问

SpringBoot自适应异常处理

客户端访问

SpringBoot自适应异常处理

划重点!!!

但是绝大部分公司的代码,都是没做自适应处理的,很大一部分原因在于,你在网上搜索Springboot全局异常处理,都是搜索到这么一段代码!

@ControllerAdvice
public class MyControllerAdvice {
 
 
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public ResponseEntity errorHandler(Exception ex) {
       // 处理异常
    }

 
}

强烈建议先用自己常用的搜索引擎搜索一遍,然后再看一下自己公司代码,看看是不是类似这么一段代码再往下看。

当然很多同学可能会说,我们就已经和客户端约定很好了,只会有json,不会有返回html的场景。所以,不做这个适应,其实也是没问题的。但是如果你是做基础架构的同学,这个功能你是必须要做的,因为你对接的是整个公司的业务部门,Springboot能做,你做类似的基础组件,如果功能比Springboot还差,你让业务方的同学怎么想?

当然,对于绝大部分同学来说,不做问题也不大。

但是这样你会错过一个很好的学习机会。什么学习机会?因为很多同学平时总说,面试造火箭,工作中遇到不懂的问题百度或者谷歌一下就好了。然而,这个问题,你就没这么好搜索到。也就是说,绝大部分人都是面向搜索引擎编程,当遇到搜索引擎无法解决的问题的时候,就是体现你价值的时候,好好珍惜。

做不做这个功能我觉得不重要,这个宝贵的锻炼解决问题能力的机会是真的很难得,毕竟,确实大部分功能是真的简单搜索,或者肥朝交流群问问就能解决。

自适应原理

很多同学说,既然搜索不到,那果断一波源码走起。但是,Springboot源码这么多,请问哪里入手?这个才是重点!这个时候,我们可以官方文档走一波。

27.1.9 Error Handling

Spring Boot provides an /error mapping by default that handles all errors in a sensible way, and it is registered as a ‘global’ error page in the servlet container. For machine clients it will produce a JSON response with details of the error, the HTTP status and the exception message. For browser clients there is a ‘whitelabel’ error view that renders the same data in HTML format (to customize it just add a View that resolves to ‘error’). To replace the default behaviour completely you can implement ErrorController and register a bean definition of that type, or simply add a bean of type ErrorAttributes to use the existing mechanism but replace the contents.

一些同学说,英文看不懂?我挑5个重点单词给你,都是小学单词,只要小学能毕业,我认为都能看懂。

clients JSON browser HTML ErrorController

肥朝小声逼逼:这里特别强调,并不是说看官方文档是最优解决问题方案。还是那句话,老司机都是看菜吃饭的,解决问题的套路有很多,时间有限,我就不把所有套路一个一个列出来(其实是怕套路全部告诉你们了,你们就取关了!),直入主题就行。

从文档和小学的英文单词我们把目标锁定在了ErrorController,给大家看一下关键代码

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {

 @RequestMapping(produces = "text/html")
 public ModelAndView errorHtml(HttpServletRequest request,
   HttpServletResponse response)
 
{
  HttpStatus status = getStatus(request);
  Map model = Collections.unmodifiableMap(getErrorAttributes(
    request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
  response.setStatus(status.value());
  ModelAndView modelAndView = resolveErrorView(request, response, status, model);
  return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
 }

 @RequestMapping
 @ResponseBody
 public ResponseEntity> error(HttpServletRequest request) {
  Map body = getErrorAttributes(request,
    isIncludeStackTrace(request, MediaType.ALL));
  HttpStatus status = getStatus(request);
  return new ResponseEntity>(body, status);
 }

}

从这里我们大致可以猜测出,要做一个自适应的全局异常处理,理论上是要这么写的。

@ControllerAdvice
public class MyExceptionHandler  {

    @ExceptionHandler(Exception.class)
    public String handleExceptionHtml(Exception e, HttpServletRequest httpServletRequest) {
        // 这里做一些你自己的处理,比如
        httpServletRequest.setAttribute("欢迎关注微信公众号","肥朝");
        return "forward:/error";
    }

}

果然调试一波,发现果真如此。当然具体怎么自定义这个错误界面之类的,网上一搜就有,所以这些不是肥朝的重点。那么这个自适应全局异常似乎美滋滋了?

遇到问题

我们知道了这个自适应的全局异常处理的原理,也很容易想到怎么弄出bug。比如,你在拦截器出现了异常的话。

@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new HandlerInterceptor() {
            @Override
            public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
                throw new RuntimeException("这里假装抛出一个肥朝异常");
                //return true;
            }

            @Override
            public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

            }

            @Override
            public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

            }
        });
    }

}

那么就会出现,StackOverflowError

因为拦截器出现异常,会掉进你的全局异常处理,然后你的全局异常处理,又进行forward,又进入了拦截器,然后一直循环。

那么怎么解决这个问题呢?我们见招拆招,这个时候,我要演示常见的几种不优雅,但是平时大家都容易做的写法。

将配置写死

registry.addInterceptor(new HandlerInterceptor() {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        throw new RuntimeException("这里假装抛出一个肥朝异常");
        //return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}).excludePathPatterns("/error");

我们从

@RequestMapping("${server.error.path:${error.path:/error}}")

这里得知,这个error.path是可以配置的,很多同学图快,excludePathPatterns处写死了/error,这样一直用默认的自然没问题,一旦人家配置了error.path,就出问题了。

潜规则

这个潜规则的问题,是绝大部分同学写代码中最常见的问题。你想一下,你的自适应全局异常是解决了,但是,带来的影响却是,每一个拦截器都要加上excludePathPatterns这么一个配置。对于使用者来说,这个必须加上某个配置,就是一种潜规则,而且,对于新来的同事而言,他根本不知道这种潜规则,一旦潜规则的代码多了,后续很难维护。

拓展思考

那么不潜规则的代码应该是怎么样的?

当然很多时候,我们必须要潜规则!比如,大数据的同学要求,送过来的日志一定要有应用名。那么,对于业务方而言,他就必须要配置应用名。那么,如何让业务方的同事知道这个潜规则。当然很多同学说,那就直接告诉同事要加某些参数啊。你连肥朝每天的推文都不记得看,你能保证每个同事都记得?

所以总结下来,我们遇到这么一类问题如下:

1.我们需要对拦截器进行一些潜规则参数,比如本文这种,如何优雅潜规则?

2.比如拦截器有顺序要求,比如我们基础框架定义了一个traceInterceptor的拦截器,这个拦截器就必须放在最前。那么问题来了,你怎么保证这个是最前的。有同学就说了,那我用@Order控制啊。那我也写一个和你一样的拦截器,叫feichaoInterceptor,代码和你一模一样,既然一模一样,你怎么保证你的就比我的前了?

3.对于必须要潜规则的场景,如何在反抗的情况下,也能潜到?

对于这几个问题,我们下期再解答。

特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:

SpringBoot自适应异常处理

SpringBoot自适应异常处理

SpringBoot自适应异常处理

长按订阅更多精彩▼

SpringBoot自适应异常处理

如有收获,点个在看,诚挚感谢

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭