天天看點

SpringMVC 之攔截器攔截器作用自定義攔截器攔截器執行流程

文章目錄

  • 攔截器作用
  • 自定義攔截器
  • 攔截器執行流程

攔截器作用

  • 日志記錄: 記錄請求資訊的日志,以便進行資訊監控、資訊統計、計算PV(Page View)等。
  • 權限檢查: 如登入檢測,進入處理器檢測檢測是否登入。
  • 性能監控: 通過攔截器在進入處理器之前記錄開始時間,在處理完後記錄結束時間,進而得到該請求的處理時間。
  • 通用行為: 讀取cookie得到使用者資訊并将使用者對象放入請求,進而友善後續流程使用,隻要是多個處理器都需要的即可使用攔截器實作。

自定義攔截器

Spring MVC 中所有的攔截器都實作/繼承自

HandlerInterceptor

接口。

HandlerInterceptor

接口的源碼如下:

public interface HandlerInterceptor {

  	// 在請求處理之前進行調用(Controller方法調用之前)
	default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return true;
	}
	
  	// 請求處理之後進行調用,但是在視圖被渲染之前(Controller方法調用之後),如果異常發生,則該方法不會被調用
	default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable ModelAndView modelAndView) throws Exception {
	}

  	// 在整個請求結束之後被調用,也就是在 DispatcherServlet 渲染了對應的視圖之後執行(主要是用于進行資源清理工作
	default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable Exception ex) throws Exception {
	}

}
           

自定義攔截器案例:

@Slf4j
@Component
public class TimeInterceptor implements HandlerInterceptor {

    private ThreadLocal<Long> threadLocalStart = new ThreadLocal<>();
    private ThreadLocal<Long> threadLocalEnd = new ThreadLocal<>();

  	// 記錄開始時間
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        long startTIme = System.currentTimeMillis();
        threadLocalStart.set(startTIme);
        log.info("開始時間:{}", startTIme);
        return true;
    }

  	// 記錄結束時間
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        long endTIme = System.currentTimeMillis();
        threadLocalEnd.set(endTIme);
        log.info("結束時間:{}", endTIme);
    }

  	// 計算接口執行時間
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        long startTime = threadLocalStart.get();
        long endTime = threadLocalEnd.get();
        log.info("接口執行時間:{} 毫秒", endTime - startTime);
    }
}
           

攔截器注冊:

@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {
    @Autowired
    private TimeInterceptor timeInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration registration = registry.addInterceptor(timeInterceptor);
        // 攔截所有請求
        registration.addPathPatterns("/**");
        // 添加不攔截路徑
        registration.excludePathPatterns("/login", "/error", "/logout","/login.html");
    }
}
           

攔截器執行流程

SpringMVC 之攔截器攔截器作用自定義攔截器攔截器執行流程

1、執行 preHandle 方法,該方法會傳回一個布爾值。如果為 false ,則結束本次請求:如果為 true 則繼續。

2、執行處理器邏輯,也就是我們的 Controller 。

3、執行 postHandle 方法。

4、執行視圖解析和視圖渲染 (直接傳回了 JSON 對象,是以沒有視圖處理)。

5、執行 afterCompletion 方法。

可以在

DispatcherServlet

doDispatch

方法的源碼中進一步驗證這個執行邏輯:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	try {
		try {
		
			// 傳回 HandlerExecutionChain  其中包含了攔截器隊列
			mappedHandler = getHandler(processedRequest);

			//調用攔截器 PreHandle 方法,若傳回 false 将直接 return
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

			// 處理 Controller
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

			// 調用攔截器的 PostHandle 方法
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}

		// 調用攔截器的 afterCompletion 方法
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
}
           

多個攔截器執行流程:

SpringMVC 之攔截器攔截器作用自定義攔截器攔截器執行流程

繼續閱讀