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

您的位置:首頁技術(shù)文章
文章詳情頁

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

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

為什么要重復(fù)造輪子

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

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

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

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

造個什么樣的輪子?

我覺得全局異常攔截應(yīng)該有如下特性

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

如何造輪子?

由于現(xiàn)在的應(yīng)用基本上都是基于spring的,因此我也是基于SpringAop來實(shí)現(xiàn)全局異常攔截

首先先定義幾個注解

@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 的作用是標(biāo)志定義異常處理器的類,方便找到異常處理器

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

@ExceptionIntercept 的作用是標(biāo)記需要異常攔截的方法

接下來定義統(tǒng)一返回格式,以便出現(xiàn)錯誤的時候統(tǒng)一返回

@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('沒有找到對應(yīng)的異常處理器')).getMethod(); } @AllArgsConstructor @Getter class ExceptionMethod { private Class<? extends Throwable> clazz; private Method method; }}

ExceptionMethod 里面有兩個屬性

clazz:這個代表著能夠處理的異常 method:代表著處理異常調(diào)用的方法

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

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

@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));}); //注冊進(jìn)spring容器 context.getBeanFactory().registerSingleton('exceptionMethodPool',exceptionMethodPool); return bean; }}

ExceptionBeanPostProcessor 通過實(shí)現(xiàn)BeanPostProcessor 接口,在bean初始化之前,把所有異常處理器塞進(jìn) ExceptionMethodPool,并把其注冊進(jìn)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,'未知錯誤')); }}

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

最后通過AOP進(jìn)行攔截

@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; }}

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

@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標(biāo)志定義異常處理器的類,然后通過@ExceptionHandler標(biāo)注處理異常的方法,方便收集

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

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

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

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

原創(chuàng)不易,如果覺得對你有幫助,麻煩點(diǎn)個贊!

我會不定期分享一些有意思的技術(shù),點(diǎn)個關(guān)注不迷路-。 -

以上就是在spring中手寫全局異常攔截器的詳細(xì)內(nèi)容,更多關(guān)于spring 全局異常攔截的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Spring
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
欧美aa在线观看| 最新亚洲国产| 国产一区二区三区91| 麻豆免费精品视频| 欧美激情视频一区二区三区免费 | 三级在线观看一区二区| 午夜在线播放视频欧美| 影音先锋久久精品| 午夜精品福利影院| 国产精品视频一区视频二区| 久久久精品区| 日韩不卡在线| 蜜臀av性久久久久蜜臀aⅴ四虎| 三级久久三级久久久| 91福利精品在线观看| 久久久亚洲欧洲日产| 中文字幕高清在线播放| 香蕉精品视频在线观看| 日韩综合一区二区| 国产乱码精品一区二区三区四区| 精品三级在线观看视频| 久久国产免费| 中文字幕av一区二区三区人| 欧美另类中文字幕| 国产成人久久精品麻豆二区| 久久久久久久久丰满| 蜜桃av一区二区在线观看| 欧美精品影院| 福利欧美精品在线| 亚洲欧美日本日韩| 国产伦精品一区二区三区视频 | 麻豆精品久久久| 久久网站免费观看| 亚洲精品看片| 国产suv精品一区| 国产亚洲毛片| 国产精品videossex久久发布| 欧美日韩视频免费观看| 亚洲精品看片| 日本在线啊啊| 亚洲精品动态| 另类专区亚洲| 中文字幕av一区二区三区人 | 欧美一级鲁丝片| 亚洲人亚洲人色久| 亚洲欧洲高清| 日本a口亚洲| 亚洲a在线视频| 日韩欧美高清一区二区三区| 美女av在线免费看| 亚洲精品看片| 欧美不卡高清一区二区三区| 日本一不卡视频| 久久青草久久| 久久国际精品| 欧美日韩视频网站| 日韩成人精品一区二区三区| 亚洲精品在线影院| 日本伊人久久| 91九色精品国产一区二区| 国产精品午夜av| 亚洲综合欧美| 特黄毛片在线观看| 欧美日韩1区| 99在线观看免费视频精品观看| 精品视频自拍| 欧美日本久久| 蜜桃久久精品一区二区| 国产手机视频一区二区| 欧美午夜精品一区二区三区电影| 久久美女性网| 日韩一级精品| 国产精品香蕉| 婷婷六月综合| 国产精品大片| 久久中文视频| 另类小说一区二区三区| 国产亚洲一区二区手机在线观看| 香蕉精品999视频一区二区| 日韩精品欧美精品| 日韩三区免费| 日韩国产在线不卡视频| 国产精品腿扒开做爽爽爽挤奶网站| 精品中文字幕一区二区三区| 国产欧美一区二区色老头| 日韩激情综合| 久久最新视频| 国产精品亚洲欧美一级在线| 国精品一区二区| 日韩一区二区三区精品视频第3页 日韩一区二区三区免费视频 | 黄色国产精品| 午夜久久中文| 久久不见久久见中文字幕免费 | 亚洲一区av| 色天使综合视频| 欧美专区18| 亚洲一级少妇| 日本不卡在线视频| 成人三级高清视频在线看| 午夜在线一区二区| 日韩欧美1区| 麻豆国产一区| 国产日产高清欧美一区二区三区| 日韩精品导航| 精品国产亚洲一区二区在线观看| 人人精品人人爱| 狠狠色狠狠色综合日日tαg| 欧美福利一区| 桃色av一区二区| 日韩在线不卡| 欧美日韩国产v| 国产免费播放一区二区| 亚洲免费毛片| 国产免费播放一区二区| 黄色网一区二区| 视频在线观看一区| 国产精品久久久一区二区| 亚洲美女久久精品| 91麻豆精品| 国产精品nxnn| 国产精品va视频| 日本不卡视频一二三区| 亚洲毛片网站| 日韩高清国产一区在线| 亚州精品视频| 中文字幕一区二区三区日韩精品| 国产精品久久久久久模特| 国产精品地址| 91亚洲精品在看在线观看高清| 噜噜噜躁狠狠躁狠狠精品视频 | 伊人久久在线| 精品在线播放| 日本国产亚洲| 国产乱子精品一区二区在线观看| 老牛影视一区二区三区| 在线亚洲成人| 视频一区在线播放| 午夜在线观看免费一区| 亚洲久久视频| 国产精品一级| 麻豆网站免费在线观看| 久久青草久久| 麻豆精品网站| 欧美日本不卡高清| 国产成人精品一区二区免费看京 | 美女久久99| 四虎成人av| 日韩另类视频| 蜜臀精品久久久久久蜜臀| 91福利精品在线观看| 丁香婷婷久久| 欧美综合另类| 亚洲精品免费观看| 精品国产美女a久久9999| 亚洲成人av观看| 中文精品电影| 精品欠久久久中文字幕加勒比| 久久精品观看| 免费成人在线视频观看| 国产精品jk白丝蜜臀av小说| 日韩综合精品| 丝袜亚洲另类欧美| 国产免费av国片精品草莓男男| а√天堂中文在线资源8| 欧美日韩三区| 欧美交a欧美精品喷水| 91精品一区二区三区综合在线爱| 日韩一区精品视频| 国产精品午夜av| 一区二区小说| 久久国产三级| 999国产精品| 欧美日韩 国产精品| 日韩精品一区二区三区免费观看| 日韩在线卡一卡二| 美女国产一区二区三区| 激情视频一区二区三区| 欧美在线观看天堂一区二区三区| 日韩理论片av| **爰片久久毛片| 国产91久久精品一区二区| 日本精品另类| 激情欧美丁香| 日韩高清不卡一区| 久久精品不卡| 日本在线精品| 影视先锋久久| 深夜福利亚洲| 精品一区二区三区四区五区| 九九九精品视频| 精品一区视频| 国产aⅴ精品一区二区四区| 国产精一区二区| 国产精品yjizz视频网| 亚洲福利免费| 亚洲免费福利一区| 日本欧美大码aⅴ在线播放| 在线观看精品| 国产精品手机在线播放| 日韩精品一区二区三区免费观看|