詳解java中spring里的三大攔截器
Filter
新建 TimeFilter
@Component
public class TimeFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("time filter init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("time filter start");
long startTime = System.currentTimeMillis();
filterChain.doFilter(servletRequest, servletResponse);
long endTime = System.currentTimeMillis();
System.out.println("time filter consume " + (endTime - startTime) + " ms");
System.out.println("time filter end");
}
@Override
public void destroy() {
System.out.println("time filter init");
}
}
啟動(dòng)服務(wù)器,在瀏覽器輸入:http://localhost:8080/hello?name=tom
可以在控制臺(tái)輸出如下結(jié)果:
time filter start
name: tom
time filter consume 3 ms
time filter end
可以看到,filter 先執(zhí)行,再到真正執(zhí)行 HelloController.sayHello() 方法。
通過(guò) TimeFilter.doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) 方法的參數(shù)可以看出,我們只能得到原始的 request 和 response對(duì)象,不能得到這個(gè)請(qǐng)求被哪個(gè) Controller 以及哪個(gè)方法處理了,使用Interceptor 就可以獲得這些信息。
Interceptor
新建 TimeInterceptor
@Component
public class TimeInterceptor extends HandlerInterceptorAdapter {
private final NamedThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<>("startTimeThreadLocal");
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("time interceptor preHandle");
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 獲取處理當(dāng)前請(qǐng)求的 handler 信息
System.out.println("handler 類:" + handlerMethod.getBeanType().getName());
System.out.println("handler 方法:" + handlerMethod.getMethod().getName());
MethodParameter[] methodParameters = handlerMethod.getMethodParameters();
for (MethodParameter methodParameter : methodParameters) {
String parameterName = methodParameter.getParameterName();
// 只能獲取參數(shù)的名稱,不能獲取到參數(shù)的值
//System.out.println("parameterName: " + parameterName);
}
// 把當(dāng)前時(shí)間放入 threadLocal
startTimeThreadLocal.set(System.currentTimeMillis());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("time interceptor postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 從 threadLocal 取出剛才存入的 startTime
Long startTime = startTimeThreadLocal.get();
long endTime = System.currentTimeMillis();
System.out.println("time interceptor consume " + (endTime - startTime) + " ms");
System.out.println("time interceptor afterCompletion");
}
}
注冊(cè) TimeInterceptor
把 TimeInterceptor 注入 spring 容器
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
private TimeInterceptor timeInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(timeInterceptor);
}
}
啟動(dòng)服務(wù)器,在瀏覽器輸入:http://localhost:8080/hello?name=tom
可以在控制臺(tái)輸出如下結(jié)果:
time filter start time interceptor preHandle handler 類:com.nextyu.demo.web.controller.HelloController handler 方法:sayHello name: tom time interceptor postHandle time interceptor consume 40 ms time interceptor afterCompletion time filter consume 51 ms time filter end
可以看到,filter 先于 interceptor 執(zhí)行,再到真正執(zhí)行 HelloController.sayHello() 方法。通過(guò) interceptor 方法上的 handler 參數(shù),我們就可以得到這個(gè)請(qǐng)求被哪個(gè) Controller 以及哪個(gè)方法處理了。但是不能直接獲取到這個(gè)方法上的參數(shù)值(在這里就是 HelloController.sayHello(String name) 方法參數(shù) name 的值),通過(guò) Aspect 就可以獲取到。
Aspcet
新建 TimeAspect
@Aspect
@Component
public class TimeAspect {
@Around("execution(* com.nextyu.demo.web.controller.*.*(..))")
public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("time aspect start");
Object[] args = pjp.getArgs();
for (Object arg : args) {
System.out.println("arg is " + arg);
}
long startTime = System.currentTimeMillis();
Object object = pjp.proceed();
long endTime = System.currentTimeMillis();
System.out.println("time aspect consume " + (endTime - startTime) + " ms");
System.out.println("time aspect end");
return object;
}
}
啟動(dòng)服務(wù)器,在瀏覽器輸入:http://localhost:8080/hello?name=tom
可以在控制臺(tái)輸出如下結(jié)果:
time filter start time interceptor preHandle handler 類:com.nextyu.demo.web.controller.HelloController handler 方法:sayHello time aspect start arg is tom name: tom time aspect consume 0 ms time aspect end time interceptor postHandle time interceptor consume 2 ms time interceptor afterCompletion time filter consume 4 ms time filter end
可以看到,filter 先執(zhí)行,再到 interceptor 執(zhí)行,再到 aspect 執(zhí)行,再到真正執(zhí)行 HelloController.sayHello() 方法。
我們也獲取到了 HelloController.sayHello(String name) 方法參數(shù) name 的值。
請(qǐng)求攔截過(guò)程圖
graph TD httprequest-->filter filter-->interceptor interceptor-->aspect aspect-->controller
- Java中過(guò)濾器 (Filter) 和 攔截器 (Interceptor)的使用
- 聊聊java 過(guò)濾器、監(jiān)聽(tīng)器、攔截器的區(qū)別(終結(jié)篇)
- 通過(guò)實(shí)例解析java過(guò)濾器和攔截器的區(qū)別
- Java中的攔截器、過(guò)濾器、監(jiān)聽(tīng)器用法詳解
- 淺析JAVA中過(guò)濾器、監(jiān)聽(tīng)器、攔截器的區(qū)別
- 了解java Struts攔截器的相關(guān)操作
- Java中的Struts2框架攔截器之實(shí)例代碼
- 應(yīng)用市場(chǎng)中Java攔截器和切面的使用實(shí)例詳解
- Java攔截器和過(guò)濾器的區(qū)別分析
相關(guān)文章
Java 超詳細(xì)講解IO操作字節(jié)流與字符流
本章具體介紹了字節(jié)流、字符流的基本使用方法,圖解穿插代碼實(shí)現(xiàn)。 JAVA從基礎(chǔ)開(kāi)始講,后續(xù)會(huì)講到JAVA高級(jí),中間會(huì)穿插面試題和項(xiàng)目實(shí)戰(zhàn),希望能給大家?guī)?lái)幫助2022-03-03
java實(shí)現(xiàn)注冊(cè)登錄系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)注冊(cè)登錄系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
Spring Boot RestTemplate提交表單數(shù)據(jù)的三種方法
本篇文章主要介紹了Spring Boot RestTemplate提交表單數(shù)據(jù)的三種方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03
基于SpringBoot實(shí)現(xiàn)大文件分塊上傳功能
這篇文章主要介紹了基于SpringBoot實(shí)現(xiàn)大文件分塊上傳功能,實(shí)現(xiàn)原理其實(shí)很簡(jiǎn)單,核心就是客戶端把大文件按照一定規(guī)則進(jìn)行拆分,比如20MB為一個(gè)小塊,分解成一個(gè)一個(gè)的文件塊,然后把這些文件塊單獨(dú)上傳到服務(wù)端,需要的朋友可以參考下2024-09-09
Spring Boot高級(jí)教程之使用Redis實(shí)現(xiàn)session共享
這篇文章主要為大家詳細(xì)介紹了Spring Boot高級(jí)教程之使用Redis實(shí)現(xiàn)session共享,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
Kylin對(duì)接JDBC集成Zepplin的實(shí)現(xiàn)方法
Zepplin是一個(gè)非常好用的編輯器工具,通過(guò)自定義編碼可以實(shí)現(xiàn)更多的業(yè)務(wù)邏輯,接下來(lái)通過(guò)本文給大家分享Kylin對(duì)接JDBC和Zepplin的操作代碼,感興趣的朋友跟隨小編一起看看吧2021-05-05
Spring Boot 3.x 全新的熱部署配置方式詳解(IntelliJ ID
這篇文章主要介紹了Spring Boot 3.x 全新的熱部署配置方式(IntelliJ IDEA 2023.1),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07
SpringCloud學(xué)習(xí)筆記之Feign遠(yuǎn)程調(diào)用
Feign是一個(gè)聲明式的http客戶端。其作用就是幫助我們優(yōu)雅的實(shí)現(xiàn)http請(qǐng)求的發(fā)送。本文將具體為大家介紹一下Feign的遠(yuǎn)程調(diào)用,感興趣的可以了解一下2021-12-12

