1、統(tǒng)一異常處理的優(yōu)勢(shì)
在開發(fā)中魏保,我們是否遇到過如下兩種奇葩現(xiàn)象:
(1)只要沒有成功熬尺,不管什么原因,前端界面給出提示:服務(wù)端錯(cuò)誤/異常谓罗。哪怕是數(shù)據(jù)校驗(yàn)不過猪杭,也這樣提示(嗯,反正先把鍋甩出去再說妥衣,具體什么原因我才不在乎呢,老子就是這么聰明)戒傻;
如果想學(xué)習(xí)Java工程化税手、高性能及分布式、深入淺出需纳。微服務(wù)芦倒、Spring,MyBatis不翩,Netty源碼分析的朋友可以加我的Java高級(jí)交流:787707172兵扬,群里有阿里大牛直播講解技術(shù)麻裳,以及Java大型互聯(lián)網(wǎng)技術(shù)的視頻免費(fèi)分享給大家。
(2)前端不做任何提示器钟,一切提示信息都來自后端津坑,成功的時(shí)候自然沒什么,失敗的時(shí)候傲霸,比如將Exception的描述信息(e.getMessage)返回疆瑰。
現(xiàn)象(1)沒什么好說的,直接拖出去槍斃吧昙啄;現(xiàn)象(2)先把產(chǎn)品經(jīng)理宰了再說吧穆役,看起來好像很專業(yè)的樣子,出了什么問題直接看response返回的結(jié)果就知道個(gè)大概梳凛,研發(fā)測(cè)試都很方便耿币,只是,大家想過沒有韧拒,研發(fā)測(cè)試運(yùn)維的問題淹接,憑什么要用戶買單,你見過淘寶京東有時(shí)候出了問題給你類似于“out of memory”的異常提示嗎叭莫?
那么異常統(tǒng)一處理有什么好處呢蹈集?
提高用戶體驗(yàn);
業(yè)務(wù)邏輯和異常處理邏輯解耦雇初;
對(duì)異常進(jìn)行分類統(tǒng)一處理拢肆,減少冗余代碼;
便于代碼風(fēng)格統(tǒng)一靖诗,并且更優(yōu)雅(比如參數(shù)校驗(yàn)的時(shí)候郭怪,得寫很多if else,并且不同的人寫法不一致)刊橘;
2鄙才、統(tǒng)一異常處理的實(shí)現(xiàn)
2.1 springboot的默認(rèn)異常處理
Spring Boot提供了一個(gè)默認(rèn)的映射:/error,當(dāng)處理中拋出異常之后促绵,會(huì)轉(zhuǎn)到該請(qǐng)求中處理攒庵,并且該請(qǐng)求有一個(gè)全局的錯(cuò)誤頁面用來展示異常內(nèi)容。
比如:
@RestController
public class Test {
@RequestMapping(value = {"/test"},method = RequestMethod.GET)
public String test(@RequestParam("id")Integer id){
return "id:"+id;
}
}
運(yùn)行后訪問結(jié)果如下:
這種直接返回錯(cuò)誤頁面败晴,對(duì)于用戶而言浓冒,顯然是太不友好了哈!
2.2 統(tǒng)一異常處理
java異常詳解
首先尖坤,定義自己的異常類稳懒,隨便起個(gè)名字哈,MyException.java
@Data
public class MyException extends Exception{
private Integer code;
private String Message;
public MyException(Integer code,String Message) {
this.code = code;
this.Message = Message;
}
}
然后定義自己的異常處理類,ExceptionHandle.java
如果想學(xué)習(xí)Java工程化慢味、高性能及分布式场梆、深入淺出墅冷。微服務(wù)、Spring或油,MyBatis寞忿,Netty源碼分析的朋友可以加我的Java高級(jí)交流:787707172,群里有阿里大牛直播講解技術(shù)装哆,以及Java大型互聯(lián)網(wǎng)技術(shù)的視頻免費(fèi)分享給大家罐脊。
如果返回的對(duì)象是JSON的話,可以用@RestControllerAdvice
@ControllerAdvice
public class ExceptionHandle {
private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result handle(Exception e) {
if (e instanceof MyException) {
MyException myException = (MyException) e;
return ResultUtil.error(boyException.getCode(), boyException.getMessage());
}else {
logger.error("【系統(tǒng)異惩汕伲】{}", e);
return new Result(-1, "未知錯(cuò)誤");
}
}
}
3萍桌、統(tǒng)一異常處理源碼解析
3.1 注解源碼解析
java注解詳解
@ControllerAdvice
@ExceptionHandler
@RestControllerAdvice與@ExceptionHandler注解是sprngmvc中與異常捕獲與處理相關(guān)的注解,它的入口也是DispatcherServlet中的doDispatcher()方法中凌简,如下:
this.processDispatchResult(processedRequest,
response, mappedHandler, mv, (Exception)dispatchException);
后面會(huì)進(jìn)入HandlerExceptionResolverComposite的resolveException方法上炎,這個(gè)ExceptionHandlerResolverComposite包含三個(gè)ExcpetionHandlerResolver,是在springmvc中生成的雏搂,在springboot中其生成代碼如下:
@Bean
public HandlerExceptionResolver handlerExceptionResolver() {
List exceptionResolvers = new ArrayList<>();
configureHandlerExceptionResolvers(exceptionResolvers);
if (exceptionResolvers.isEmpty()) {
addDefaultHandlerExceptionResolvers(exceptionResolvers);
}
extendHandlerExceptionResolvers(exceptionResolvers);
HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
composite.setOrder(0);
composite.setExceptionResolvers(exceptionResolvers);
return composite;
}
后面他會(huì)進(jìn)入ExceptionHandlerExceptionResolver類的方法:
protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
HttpServletResponse response, @Nullable HandlerMethod handlerMethod,
Exception exception) {
ServletInvocableHandlerMethod exceptionHandlerMethod =
getExceptionHandlerMethod(handlerMethod, exception);
}
在這個(gè)方法中的第一行藕施,getExceptionHandlerMethod方法,其進(jìn)行了查找對(duì)應(yīng)的帶有@ControllerAdvice注解的類型和對(duì)應(yīng)匹配的方法凸郑,然后在doResolverHandlerMethod方法中進(jìn)行了處理裳食,這就是整個(gè)流程。
@ControllerAdvice的加載過程:
首先在springboot掃描的時(shí)候芙沥,會(huì)把@ControllerAdvice的bean放入到beanFactory里面去诲祸,此時(shí)只要從beanFactory中獲取到需要的bean即可,處理方式在ExceptionHandlerExceptionResolver類中:
@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBodyAdvice beans
initExceptionHandlerAdviceCache();
private void initExceptionHandlerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
if (logger.isDebugEnabled()) {
logger.debug("Looking for exception mappings: " + getApplicationContext());
}
List adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
封裝好后而昨,獲取帶有@Exceptionhandler的注解方法救氯,即根據(jù)異常類型進(jìn)行調(diào)用了。
歡迎工作一到八年的Java工程師朋友們加入Java高級(jí)交流:787707172
本群提供免費(fèi)的學(xué)習(xí)指導(dǎo) 架構(gòu)資料 以及免費(fèi)的解答
不懂得問題都可以在本群提出來 之后還會(huì)有直播平臺(tái)和講師直接交流噢