春天使用编写一个全局异常拦截器

  介绍

本篇文章给大家分享的是有关使用弹簧编写一个全局异常拦截器,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

<强>为什么要重复造轮子

你可能会问,春天已经自带了全局异常拦截,为什么还要重复造轮子呢?

这是个好问题,我觉得有以下几个原因

    <李>装逼李 <李>春季的全局异常拦截只是针对于spring MVC的接口,对于你的RPC接口就无能为力了李 <>李无法定制化李 <李>除了写业务代码,我们其实还能干点别的事
      李,

我觉得上述理由已经比较充分的解答了为什么要重复造轮子,接下来就来看一下怎么造轮子

<强>造个什么样的轮子?

我觉得全局异常拦截应该有如下特性

    <李>使用方便,最好和春天原生的使用方式一致,降低学习成本 <李>能够支持所有接口 <李>调用异常处理器可预期,比如说定义了RuntimeException的处理器和异常的处理器,如果这个时候抛出NullPointException,这时候要能没有歧义的选择预期的处理器
      李,

<>强如何造轮子?

由于现在的应用基本上都是基于春天的,因此我也是基于SpringAop来实现全局异常拦截

首先先定义几个注解

@Target (ElementType.TYPE)   @Retention (RetentionPolicy.RUNTIME)   @Documented   @ component   公共@ interface ExceptionAdvice {   }      @Target (ElementType.METHOD)   @Retention (RetentionPolicy.RUNTIME)   @Documented   公共@ interface ExceptionHandler {   Class<及# 63;扩展Throwable>[]值();   }      @Target (ElementType.METHOD)   @Retention (RetentionPolicy.RUNTIME)   @Documented   公共@ interface ExceptionIntercept {   }

@ExceptionAdvice的作用是标志定义异常处理器的类,方便找到异常处理器

@ExceptionHandler的作用是标记某个方法是处理异常的,里面的值是能够处理的异常类型

@ExceptionIntercept的作用是标记需要异常拦截的方法

接下来定义统一返回格式,以便出现错误的时候统一返回

@ data   公开课BaseResponse{   私人整数代码;   私人字符串消息;   私人T数据;      公共BaseResponse(整数代码字符串消息){   这一点。代码=代码;   这一点。消息=消息;   }   }

然后定义一个收集异常处理器的类

公共类ExceptionMethodPool {
  私人List方法;
  私有对象excutor;
  
  公共ExceptionMethodPool(对象excutor) {
  这一点。方法=new ArrayList ();
  这一点。excutor=excutor;
  }
  
  公共对象getExcutor () {
  返回excutor;
  }
  
  公共空间添加(Class<及# 63;Throwable>延伸;clazz方法方法){
  方法。添加(新ExceptionMethod (clazz、方法));
  }//按序查找能够处理该异常的处理器
  公共方法obtainMethod (Throwable Throwable) {
  返回的方法
  .stream ()
  .filter (e→e.getClazz () .isAssignableFrom (throwable.getClass ()))
  .findFirst ()
  .orElseThrow(()→新RuntimeException(“没有找到对应的异常处理器“))
  .getMethod ();
  }
  
  @AllArgsConstructor
  @ getter
  类ExceptionMethod {
  私人Class<及# 63;Throwable>延伸;clazz;
  私有方法方法;
  }
  }

ExceptionMethod里面有两个属性

    <李> clazz:这个代表着能够处理的异常李 <李>方法:代表着处理异常调用的方法
      李,

ExceptionMethodPool里面按序存放所有异常处理器,excutor是执行这些异常处理器的对象

接下来把所有定义的异常处理器收集起来

@ component   公共类ExceptionBeanPostProcessor实现BeanPostProcessor {   私人ExceptionMethodPool ExceptionMethodPool;   @ autowired   私人ConfigurableApplicationContext上下文;      @Override   公共对象postProcessBeforeInitialization(对象bean,字符串beanName)抛出BeansException {   Class<及# 63;比;clazz=bean.getClass ();   ExceptionAdvice建议=clazz.getAnnotation (ExceptionAdvice.class);   如果返回bean(建议==null);   如果(exceptionMethodPool !=null)把新RuntimeException(“不允许有两个异常定义类“);   exceptionMethodPool=new exceptionMethodPool (bean);//保持处理异常方法顺序   Arrays.stream (clazz.getDeclaredMethods ())   .filter(方法→method.getAnnotation (ExceptionHandler.class) !=null)   .forEach(方法→{   ExceptionHandler ExceptionHandler=method.getAnnotation (ExceptionHandler.class);   Arrays.stream (exceptionHandler.value ())。forEach (c→exceptionMethodPool.add (c,方法));   });//注册进春容器   context.getBeanFactory () .registerSingleton (“exceptionMethodPool" exceptionMethodPool);   返回bean;   }   }

春天使用编写一个全局异常拦截器