Spring異常解析原始碼分析
微信公眾號:
關注回覆java 1024G最新java學習資料(包含大資料資料)免費領;
異常處理重要性
- 良好的異常處理體系,便於對程式的後期維護
- 當發生錯誤時,程式不至於崩潰,提高程式健壯性
- 當發生錯誤時,可以在短時間內找定位問題所在
- 當發生錯誤時,避免異常棧裸奔,暴露底層架構,提高專案安全性
Spring統一異常方式
- 使用 @ ExceptionHandler 註解(缺點:異常處理的方法必須與出錯的方法在同一個Controller裡面,不能全域性處理)
1 // 需要捕捉的異常 2 @ExceptionHandler({ BizException.class }) 3 // Value用於設定response的狀態碼,例如404,200等,reason用於響應,可以是內容語句。 4 @ResponseStatus(code=HttpStatus.BAD_REQUEST,reason="bad request") 5 // 可以返回Json也可以進行跳轉 6 @ResponseBody 7 public ServerResponse<?> exception(BizException e) { 8 return ServerResponse.createByErrorMessage(e.getMessage()); 9 }
- 實現 HandlerExceptionResolver 介面
11 @Component 2 public class GlobalExceptionResolver implements HandlerExceptionResolver{ 3 4 public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { 5 //Object handler ----> HandlerMethod 也可能為null 6 // 可以通過handler進行特定處理 7 .............. 8 } 9}
- 使用@ControllerAdvice+ @ ExceptionHandler註解
[email protected] [email protected] 3public class GlobalExceptionResolver { 4 @ResponseStatus(HttpStatus.BAD_REQUEST) 5 // 可以不指定特定的異常即預設攔截所有異常 6 @ExceptionHandler(HttpMessageNotReadableException.class) 7 public ServiceResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e) { 8 return ServerResponse.createByErrorMessage(e.getMessage()) 9 } 10 // 其他程式碼省略 11}
SpringMVC異常處理原始碼剖析
- 從DispatcherServlet的doDispatch方法入手
1protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
2 try {
3 //省略請求處理程式碼部分
4 }catch (Exception ex) {
5 dispatchException = ex;
6 }
7 // 捕捉異常後呼叫processDispatchResult方法
8 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
9 }
10 finally {
11
12 }
13 }
- processDispatchResult如何處理呢
1private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
2 HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
3 // 先判斷異常是否為null
4 if (exception != null) {
5 if (exception instanceof ModelAndViewDefiningException) {
6 logger.debug("ModelAndViewDefiningException encountered", exception);
7 mv = ((ModelAndViewDefiningException) exception).getModelAndView();
8 }else {
9 Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
10 mv = processHandlerException(request, response, handler, exception);
11 errorView = (mv != null);
12 }
13 }
14 }
- processHandlerException核心程式碼
1protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
2 Object handler, Exception ex) throws Exception {
3 // 省略了不關係部分(異常解析器排序)
4 ModelAndView exMv = null;
5 for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
6 // 呼叫resolveException方法
7 // Spring 自帶的異常處理器暫時不講本質上和我們自定義差不多
8 exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
9 if (exMv != null) {
10 // 只要獲取ModeAndView終止處理
11 break;
12 }
13 }
14 // 如果沒獲得直接丟擲異常
15 throw ex;
16 }
- Spring自帶異常解析器主要介面和實現類
- AbstractHandlerMethodExceptionResolver和ExceptionHandlerExceptionResolver負責解析@ExceptionHandle
- ResponseStatusExceptionResolver解析@ResponseStatus
- DefaultHandlerExceptionResolver按照不同的型別分別對異常進行解析
- SimpleMappingExceptionResolver: 通過配置的異常類和view的對應關係來解析異常
攔截404
上面介紹的方法並不能攔截404,為什麼要攔截404呢?首先為了產品的安全,不隨便暴露後臺所用的中介軟體,避免黑客利用中介軟體本身的漏洞攻擊網站,另外也可以專案與使用者有良好的互動。
-
利用Spring MVC的最精確匹配原則(@requestMapping("*)攔截的這個方法返回一個自定義的404介面)
-
利用web容器提供的error-page
1<error-page>
2 // 也可以攔截其他錯誤碼比如500
3 <error-code>404</error-code>
4 // 確保resource目錄不被spring攔截
5 <location>/resource/view/404.htm</location>
6 </error-page>
- 重寫DispatcherServlet的noHandlerFound方法
1protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception{
2 if(pageNotFoundLogger.isWarnEnabled())
3 pageNotFoundLogger.warn((new StringBuilder()).append("No mapping found for HTTP request with URI [").append(getRequestUri(request)).append("] in DispatcherServlet with name '").append(getServletName()).append("'").toString());
4 if(throwExceptionIfNoHandlerFound){
5 throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request), (new ServletServerHttpRequest(request)).getHeaders());
6 } else{
7 //response.sendError(404);
8 // return;
9 // 修改為
10 // 定義一個請求路徑為404的Controller方法
11 response.sendRedirect(request.getContextPath() + "/404");
12 }
13 }
專案中異常處理方案
[email protected]
2public class GlobalExceptionResolver implements HandlerExceptionResolver {
3
4 public static final String AJAX="X-Requested-With";
5
6 public ModelAndView resolveException(HttpServletRequest request,
7 HttpServletResponse response, Object handler, Exception ex) {
8 // 區分是否是ajax請求
9 boolean isAjax = isAjax(request);
10 return handleException(request,response,handler,ex,isAjax);
11 }
12 /**
13 * 判斷當前請求是否為非同步請求.
14 * @param request
15 * @param response
16 * @return boolean
17 * @author zhaoxin
18 * @date 2018年9月18日 上午10:59:35
19 */
20 private boolean isAjax(HttpServletRequest request){
21 return StrUtil.isNotBlank(request.getHeader(AJAX));
22 }
23 /**
24 * 處理異常
25 * @return ModelAndView
26 * @author zhaoxin
27 * @date 2018年9月18日 上午11:52:40
28 */
29 private ModelAndView handleException(HttpServletRequest request,
30 HttpServletResponse response, Object handler,
31 Throwable ex, boolean isajax) {
32 //異常資訊記錄到日誌檔案中
33 LogUtil.logError("Capture global exceptions:"+ex.getMessage());
34 LogUtil.logException(ex);
35 //分普通請求和ajax請求分別處理
36 if(isajax){
37 return handleAjax(request,response,handler,ex);
38 }else{
39 return handlerNotAjax(request,response,handler,ex);
40 }
41 }
42
43 /**
44 * ajax異常處理並返回.
45 * @param request
46 * @param response
47 * @param handler
48 * @param initialEx
49 */
50 private ModelAndView handleAjax(HttpServletRequest request,
51 HttpServletResponse response, Object handler,Throwable initialEx){
52 response.setHeader("Cache-Control", "no-store");
53 // 返回JsonView
54 ModelAndView mav = new ModelAndView(new FastJsonJsonView());
55 mav.addObject("msg", "System exceptions please check logs");
56 mav.addObject("status", Const.RespondeCode.ERROR.getCode());
57 mav.addObject("success",false);
58 return mav;
59 }
60 /**
61 * 普通頁面異常處理並返回.
62 * @param request
63 * @param response
64 * @param handler
65 * @param deepestException
66 * @return
67 */
68 private ModelAndView handlerNotAjax(HttpServletRequest request,HttpServletResponse response, Object handler, Throwable ex) {
69 Map<String, Object> model = new HashMap<>();
70 model.put("message", "System exceptions please check logs");
71 model.put("ex", ex);
72 return new ModelAndView("common/error500", model);
73 }
74
75
76}
求關注
相關推薦
Spring異常解析原始碼分析
微信公眾號: 關注回覆java 1024G最新java學習資料(包含大資料資料)免費領; 異常處理重要性 良好的異常處理體系,便於對程式的後期維護 當發生錯誤時,程式不至於崩潰,提高程式健壯性 當發生錯誤時,可以在短時間內找定位問題所在 當發生錯誤時,避免異常棧
深入研究Spring-IoC:原始碼分析依賴注入
1.前言 對於容器建立的過程已經闡述過一遍了,下面是依賴注入的問題。Spring提供的依賴注入的方法主要由兩種:一種是通過getBean的方法;另一種是通過註解@Autowaire。 需要指出的是依賴注入的過程是使用者第一次向ioc容器索要Bean的時候開始生產的,也可以通過設定
深入研究Spring-IoC:原始碼分析容器建立
1.前言 從之前的分析中可以知道IOC容器的建立大致分為3步:Resource定位、BeanDefinition載入解析、向容器註冊BeanDefinition。 Tiny-spring手動實現了Spring框架,通過對這個原始碼的解讀可以更好更有效的理解Spring。 2.
Spring Developer Tools 原始碼分析:三、重啟自動配置'
接上文 Spring Developer Tools 原始碼分析:二、類路徑監控,接下來看看前面提到的這些類是如何配置,如何啟動的。 spring-boot-devtools 使用了 Spring Boot 的自動配置方式,我們先關注本地開發環境中自動重啟的部分。 在 LocalDevToolsAut
Spring Cloud Zuul原始碼分析
如何使用Spring Cloud Zuul? 之前的文章中,我們學習了Spring Cloud Zuul如何使用,這裡再回顧下: 1.引入依賴,在啟動類中新增@EnableZuulProxy,宣告這是一個Zuul代理。 2.註冊到Eureka Server,啟動服務,訪問這個埠,ur
spring-boot-admin原始碼分析及單機監控spring-boot-monitor的實現(三)
SpringBootMonitor spring-boot-admin原始碼分析及單機監控spring-boot-monitor的實現(一) spring-boot-admin原始碼分析及單機監控spring-boot-monitor的實現(二)
spring-boot-admin原始碼分析及單機監控spring-boot-monitor的實現(二)
SpringBootMonitor spring-boot-admin原始碼分析及單機監控spring-boot-monitor的實現(一) spring-boot-admin原始碼分析及單機監控spring-boot-monitor的實現(二)
spring-boot-admin原始碼分析及單機監控spring-boot-monitor的實現(一)
SpringBootMonitor spring-boot-admin原始碼分析及單機監控spring-boot-monitor的實現(一) spring-boot-admin原始碼分析及單機監控spring-boot-monitor的實現(二) spring-boot-ad
深入分析集合併發修改異常(原始碼分析)java.util.ConcurrentModificationException
在我們迭代操作集合時,有時可能需要改變集合的元素,若操作不當,經常都會出現不正確的結果或者併發操作異常,如下: Exception in thread "main" java.util.ConcurrentModificatio
spring事務管理原始碼分析(一)配置和事務增強代理的生成流程
在本篇文章中,將會介紹如何在spring中進行事務管理,之後對其內部原理進行分析。主要涉及 @EnableTransactionManagement註解為我們做了什麼? 為什麼標註了@Transactional註解的方法就可以具有事務的特性,保持了資料的ACID特性?spring到底是如何具有這樣
Android7.1 [Camera] cam_board.xml 檔案解析原始碼分析(一)
原始碼平臺:rk3399 RK支援了很多個攝像頭,在驅動目錄hardware/rockchip/camer
spring mvc核心原始碼分析
前言 自研究了spring security核心原始碼以來,在實踐使用的基礎上更為深入的學習了它的思想.我的java世界彷彿被打開了一扇大門,開始對研究原始碼有種渴望.打算先看一輪核心原始碼,滿足目前工作需要,待對boot有個整體的瞭解之後再逐個細細研究 spring m
Spring component-scan原始碼分析(一)
在XML中配置component-scan通常如下 <context:component-scan base-package="xxx"> <context:exclude-filter type="annotation" expressio
Spring component-scan原始碼分析(二) -- @Configuration註解處理
上篇文章Spring component-scan原始碼分析(一) – XML解析分析了Spring解析<context:component-scan …/>標籤時,把掃描到的合適的類封裝成BeanDefinition加入Sping容器中,本篇分析S
Spring component-scan原始碼分析(三) -- @Autowired等註解的處理
本篇文章分析注入註解(@Autowired、@Value等)的處理,其邏輯在AutowiredAnnotationBeanPostProcessor類中。 可以看到AutowiredAnnotationBeanPostProcessor類實現了一些增強處理的
Spring-Cloud-Gateway原始碼分析系列| Spring-Cloud-Gateway初始化
推薦 Spring Boot/Cloud 視訊: Spring-Cloud專案使用EnableAutoConfiguration註解自動 初始化配置資訊,Spring-Cloud-Gateway同樣,Spring-Cloud-Gateway下的spring.f
Spring-Cloud-Gateway原始碼分析系列 | Spring-Cloud-Gateway之GatewayProperties初始化載入
推薦 Spring Boot/Cloud 視訊: 在Spring-Cloud-Gateway初始化時我們在GatewayAutoConfiguration配置中看到了有初始化載入GatewayProperties例項的配置,接下來學習下GatewayPrope
spring事物--04原始碼分析-事務處理攔截器的實現分析
事務處理攔截器的實現分析 通過上面的分析,很明確spring在事務方面aop是怎麼玩的了。那麼真正要處理事務是ProxyFactory.getObject() 方法返回的代理物件,通過呼叫代理物件的方法時,攔截器有一個invoker() 方法會被回撥(aop的玩法)。
Spring Core Container 原始碼分析三:Spring Beans 初始化流程分析
前言 本文是筆者所著的 Spring Core Container 原始碼分析系列之一; 本篇文章主要試圖梳理出 Spring Beans 的初始化主流程和相關核心程式碼邏輯; 本文轉載自本人的部落格,傷神的部落格 http://www.shangyang.me/2017/
Spring Core Container 原始碼分析七:註冊 Bean Definitions
前言 原本以為,Spring 通過解析 bean 的配置,生成並註冊 bean defintions 的過程不太複雜,比較簡單,不用單獨開闢一篇博文來講述;但是當在分析前面兩個章節有關 @Autowired、@Component、@Service 註解的注入機制的時候,發現,如果沒有對有關 bea