- 在進入處理器之前記錄開始時間,即在攔截器的 preHandle 記錄開始時間糖荒;
- 在結(jié)束請求處理之后記錄結(jié)束時間杉辙,即在攔截器的 afterCompletion 記錄結(jié)束實現(xiàn),并用結(jié)束時間-開始時間得到這
次請求的處理時間捶朵。
問題:
我們的攔截器是單例蜘矢,因此不管用戶請求多少次都只有一個攔截器實現(xiàn),即線程不安全综看,那我們應(yīng)該怎么記錄時間呢品腹?
解決方案是使用 ThreadLocal,它是線程綁定的變量红碑,提供線程局部變量(一個線程一個 ThreadLocal珍昨,A 線程的ThreadLocal 只能看到 A 線程的 ThreadLocal,不能看到 B 線程的 ThreadLocal)
代碼
public class StopWatchHandlerInterceptor extends HandlerInterceptorAdapter {
private NamedThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<Long>("StopWatch-StartTime");
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception {
long beginTime = System.currentTimeMillis();//1句喷、開始時間
startTimeThreadLocal.set(beginTime);//線程綁定變量(該數(shù)據(jù)只有當前請求的線程可見)
return true;//繼續(xù)流程
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,Object handler, Exception ex) throws Exception {
long endTime = System.currentTimeMillis();//2镣典、結(jié)束時間
long beginTime = startTimeThreadLocal.get();//得到線程綁定的局部變量(開始時間)
long consumeTime = endTime - beginTime;//3、消耗的時間
if(consumeTime > 500) {//此處認為處理時間超過500毫秒的請求為慢請求
//TODO 記錄到日志文件
System.out.println(String.format("%s consume %d millis", request.getRequestURI(), consumeTime));
}
}
}