文章目錄
- 攔截器作用
- 自定義攔截器
- 攔截器執行流程
攔截器作用
- 日志記錄: 記錄請求資訊的日志,以便進行資訊監控、資訊統計、計算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");
}
}
攔截器執行流程
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);
}
}
多個攔截器執行流程: