日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

在spring中手寫全局異常攔截器

瀏覽:26日期:2023-08-02 13:16:22

為什么要重復造輪子

你可能會問,Spring已經自帶了全局異常攔截,為什么還要重復造輪子呢?

這是個好問題,我覺得有以下幾個原因

裝逼 Spring的全局異常攔截只是針對于Spring MVC的接口,對于你的RPC接口就無能為力了 無法定制化 除了寫業務代碼,我們其實還能干點別的事

我覺得上述理由已經比較充分的解答了為什么要重復造輪子,接下來就來看一下怎么造輪子

造個什么樣的輪子?

我覺得全局異常攔截應該有如下特性

使用方便,最好和spring原生的使用方式一致,降低學習成本 能夠支持所有接口 調用異常處理器可預期,比如說定義了RuntimeException的處理器和Exception的處理器,如果這個時候拋出NullPointException,這時候要能沒有歧義的選擇預期的處理器

如何造輪子?

由于現在的應用基本上都是基于spring的,因此我也是基于SpringAop來實現全局異常攔截

首先先定義幾個注解

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface ExceptionAdvice {}@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface ExceptionHandler { Class<? extends Throwable>[] value();}@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface ExceptionIntercept {}

@ExceptionAdvice 的作用是標志定義異常處理器的類,方便找到異常處理器

@ExceptionHandler 的作用是標記某個方法是處理異常的,里面的值是能夠處理的異常類型

@ExceptionIntercept 的作用是標記需要異常攔截的方法

接下來定義統一返回格式,以便出現錯誤的時候統一返回

@Datapublic class BaseResponse<T> { private Integer code; private String message; private T data; public BaseResponse(Integer code, String message) { this.code = code; this.message = message; }}

然后定義一個收集異常處理器的類

public class ExceptionMethodPool { private List<ExceptionMethod> methods; private Object excutor; public ExceptionMethodPool(Object excutor) { this.methods = new ArrayList<ExceptionMethod>(); this.excutor = excutor; } public Object getExcutor() { return excutor; } public void add(Class<? extends Throwable> clazz, Method method) { methods.add(new ExceptionMethod(clazz, method)); } //按序查找能夠處理該異常的處理器 public Method obtainMethod(Throwable throwable) { return methods.stream().filter(e -> e.getClazz().isAssignableFrom(throwable.getClass())).findFirst().orElseThrow(() ->new RuntimeException('沒有找到對應的異常處理器')).getMethod(); } @AllArgsConstructor @Getter class ExceptionMethod { private Class<? extends Throwable> clazz; private Method method; }}

ExceptionMethod 里面有兩個屬性

clazz:這個代表著能夠處理的異常 method:代表著處理異常調用的方法

ExceptionMethodPool 里面按序存放所有異常處理器,excutor是執行這些異常處理器的對象

接下來把所有定義的異常處理器收集起來

@Componentpublic class ExceptionBeanPostProcessor implements BeanPostProcessor { private ExceptionMethodPool exceptionMethodPool; @Autowired private ConfigurableApplicationContext context; @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { Class<?> clazz = bean.getClass(); ExceptionAdvice advice = clazz.getAnnotation(ExceptionAdvice.class); if (advice == null) return bean; if (exceptionMethodPool != null) throw new RuntimeException('不允許有兩個異常定義類'); exceptionMethodPool = new ExceptionMethodPool(bean); //保持處理異常方法順序 Arrays.stream(clazz.getDeclaredMethods()).filter(method -> method.getAnnotation(ExceptionHandler.class) != null).forEach(method -> { ExceptionHandler exceptionHandler = method.getAnnotation(ExceptionHandler.class); Arrays.stream(exceptionHandler.value()).forEach(c -> exceptionMethodPool.add(c,method));}); //注冊進spring容器 context.getBeanFactory().registerSingleton('exceptionMethodPool',exceptionMethodPool); return bean; }}

ExceptionBeanPostProcessor 通過實現BeanPostProcessor 接口,在bean初始化之前,把所有異常處理器塞進 ExceptionMethodPool,并把其注冊進Spring容器

然后定義異常處理器

@Componentpublic class ExceptionProcessor { @Autowired private ExceptionMethodPool exceptionMethodPool; public BaseResponse process(Throwable e) { return (BaseResponse) FunctionUtil.computeOrGetDefault(() ->{ Method method = exceptionMethodPool.obtainMethod(e); method.setAccessible(true); return method.invoke(exceptionMethodPool.getExcutor(),e); },new BaseResponse(0,'未知錯誤')); }}

這里應用了我自己通過函數式編程封裝的一些語法糖,有興趣的可以看下

最后通過AOP進行攔截

@Aspect@Componentpublic class ExceptionInterceptAop { @Autowired private ExceptionProcessor exceptionProcessor; @Pointcut('@annotation(com.example.exception.intercept.ExceptionIntercept)') public void pointcut() { } @Around('pointcut()') public Object around(ProceedingJoinPoint point) { return computeAndDealException(() -> point.proceed(),e -> exceptionProcessor.process(e)); } public static <R> R computeAndDealException(ThrowExceptionSupplier<R> supplier, Function<Throwable, R> dealFunc) { try { return supplier.get(); } catch (Throwable e) { return dealFunc.apply(e); } } @FunctionalInterface public interface ThrowExceptionSupplier<T> { T get() throws Throwable; }}

到這里代碼部分就已經完成了,我們來看下如何使用

@ExceptionAdvicepublic class ExceptionConfig { @ExceptionHandler(value = NullPointerException.class) public BaseResponse process(NullPointerException e){ return new BaseResponse(0,'NPE'); } @ExceptionHandler(value = Exception.class) public BaseResponse process(Exception e){ return new BaseResponse(0,'Ex'); } }@RestControllerpublic class TestControler { @RequestMapping('/test') @ExceptionIntercept public BaseResponse test(@RequestParam('a') Integer a){ if (a == 1){ return new BaseResponse(1,a+''); } else if (a == 2){ throw new NullPointerException(); } else throw new RuntimeException(); }}

我們通過@ExceptionAdvice標志定義異常處理器的類,然后通過@ExceptionHandler標注處理異常的方法,方便收集

最后在需要異常攔截的方法上面通過@ExceptionIntercept進行異常攔截

我沒有使用Spring那種匹配最近父類的方式尋找匹配的異常處理器,我覺得這種設計是一個敗筆,理由如下

代碼復雜 不能一眼看出要去調用哪個異常處理器,尤其是定義的異常處理器非常多的時候,要是弄多個定義類就更不好找了,可能要把所有的處理器看完才知道應該調用哪個

出于以上考慮,我只保留了一個異常處理器定義類,并且匹配順序和方法定義順序一致,從上到下依次匹配,這樣只要找到一個能夠處理的處理器,那么就知道了會如何調用

原創不易,如果覺得對你有幫助,麻煩點個贊!

我會不定期分享一些有意思的技術,點個關注不迷路-。 -

以上就是在spring中手寫全局異常攔截器的詳細內容,更多關于spring 全局異常攔截的資料請關注好吧啦網其它相關文章!

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
成人在线超碰| 日韩中文字幕区一区有砖一区| av在线资源| 日韩精彩视频在线观看| 蜜臀av性久久久久蜜臀aⅴ四虎| 在线成人动漫av| 久久久久久久久久久妇女| 婷婷成人综合| 激情欧美一区| 国产精品腿扒开做爽爽爽挤奶网站| 国产一区久久| 亚洲日韩中文字幕一区| 日韩不卡在线观看日韩不卡视频| 青青草国产成人99久久| 麻豆精品在线视频| 色乱码一区二区三区网站| 日韩.com| 野花国产精品入口| 美女被久久久| 国产欧美综合一区二区三区| 麻豆极品一区二区三区| 日韩久久精品网| 国产亚洲一级| 欧美激情一区| 99热精品久久| 欧美亚洲自偷自偷| 久久久成人网| 91成人小视频| av亚洲在线观看| 日韩av不卡在线观看| 亚洲风情在线资源| 日韩精品亚洲aⅴ在线影院| 久久精品国产亚洲aⅴ| 成人精品视频| 日韩欧美美女在线观看| 久久国产电影| 麻豆91在线播放| 六月婷婷一区| 久久久精品网| 麻豆精品99| 亚洲18在线| 国产在线|日韩| 九九99久久精品在免费线bt| 黄色精品网站| 欧美精品资源| 国产精品美女在线观看直播| 久久先锋影音| 久久天堂成人| 久久字幕精品一区| 视频一区国产视频| 91国语精品自产拍| 亚洲成人va| 亚洲性色av| 国产一区二区三区视频在线| 91在线成人| 日本中文字幕视频一区| 日韩一级网站| 亚洲先锋成人| 国产精品88久久久久久| 日韩国产综合| 日韩伦理福利| 欧美日韩中文一区二区| 欧美sss在线视频| 精品美女在线视频| 色综合五月天| 蜜桃av.网站在线观看| 成人av三级| 亚洲国产综合在线看不卡| 日本精品在线中文字幕| 亚洲一级二级| 自拍日韩欧美| 亚洲精品免费观看| 久久gogo国模啪啪裸体| 91亚洲国产| 一区福利视频| 亚洲3区在线| 欧美亚洲专区| 日韩在线观看| 久久免费黄色| 日韩在线播放一区二区| 国产精品亚洲综合色区韩国| 日韩av免费大片| 国产精品腿扒开做爽爽爽挤奶网站| 日韩中文字幕麻豆| 精品视频网站| 红桃视频国产精品| 欧美日韩亚洲一区三区| 久久久精品网| 欧美精品影院| 亚洲福利精品| 欧美一区二区三区免费看| 欧美日韩在线网站| 国产精品尤物| 91精品亚洲| 久久精品99国产精品| 成人va天堂| 国产精品毛片aⅴ一区二区三区| 国产综合色产| 麻豆91精品91久久久的内涵| 一区二区自拍| 日韩在线看片| 久久精品国产999大香线蕉| 91精品啪在线观看国产18| 国产高清精品二区| 欧美久久亚洲| 亚洲性视频在线| 伊人久久婷婷| 日韩激情一区| 国产精品综合色区在线观看| 日韩视频一区二区三区在线播放免费观看| 国产色噜噜噜91在线精品| 激情久久婷婷| 韩国精品主播一区二区在线观看 | 日本午夜免费一区二区 | 日韩激情精品| 视频一区视频二区中文| 国产日韩综合| 蜜桃成人精品| 六月婷婷综合| 亚洲欧洲高清| 秋霞影院一区二区三区| 日本а中文在线天堂| 高清一区二区三区av| 精品一区二区三区视频在线播放| 日韩中文av| 91午夜精品| 免费在线欧美黄色| 国产精品sm| 久久精品日韩欧美| 国产粉嫩在线观看| 99久久激情| 亚洲一区二区三区免费在线观看| 免费视频一区三区| 亚洲二区三区不卡| 亚洲一区亚洲| 综合日韩在线| 国产精品夜夜夜| 国产一区二区三区四区| 日韩在线中文| 国产精品毛片| 日韩欧美久久| 精品国产aⅴ| 在线视频观看日韩| 婷婷亚洲成人| 成人午夜在线| 欧美日韩国产亚洲一区| 亚洲91在线| 超碰在线99| 久久久777| 国产精品亚洲综合在线观看| 日韩欧美一区二区三区在线视频 | 国产精品成人a在线观看| 免费国产自久久久久三四区久久 | 高清日韩中文字幕| 羞羞答答国产精品www一本| 亚洲精品一二| 国产成人精品999在线观看| 欧美日韩激情| 国产欧美综合一区二区三区| 999国产精品| 国产日韩高清一区二区三区在线| 桃色av一区二区| 日韩高清在线观看一区二区| 四季av一区二区凹凸精品| 免费视频一区二区| 日韩欧美一区免费| 国产欧美自拍| 男女性色大片免费观看一区二区 | 亚洲午夜久久| sm捆绑调教国产免费网站在线观看| 久久最新视频| 少妇久久久久| 久久av影视| 婷婷精品久久久久久久久久不卡| 九九精品调教| 成午夜精品一区二区三区软件| 91久久精品无嫩草影院| 人人精品人人爱| 最新亚洲一区| 久久视频一区| 久久精品国内一区二区三区| 欧美伊人影院| 日韩精品亚洲专区在线观看| 视频一区二区国产| 免费日韩一区二区| 欧美日韩日本国产亚洲在线 | 国产精品久久亚洲不卡| 日韩精品视频一区二区三区| 亚洲欧美激情诱惑| 亚洲国内精品| 亚洲a一区二区三区| 青青青免费在线视频| 欧美日韩网址| 久久亚洲国产精品尤物| 国产精品网站在线看| 久久激情综合网| 日韩欧美中文字幕电影| 亚洲一区导航| 日韩av影院| 国产日产精品_国产精品毛片 |