??在工作中使用Web框架,總是避免不了與這些概念打交道,做一下總結(jié),一口氣說完攔截器、過濾器、監(jiān)聽器。
1. 攔截器、過濾器、監(jiān)聽器區(qū)別
- 攔截器(interceptor):依賴于web框架,基于Java的反射機(jī)制,屬于AOP的一種應(yīng)用。一個(gè)攔截器實(shí)例在一個(gè)controller生命周期內(nèi)可以多次調(diào)用。只能攔截Controller的請求。
- 過濾器(Filter):依賴于Servlet容器,基于函數(shù)回掉,可以對幾乎所有請求過濾,一個(gè)過濾器實(shí)例只能在容器初使化調(diào)用一次。
- 監(jiān)聽器(Listener):web監(jiān)聽器是Servlet中的特殊的類,用于監(jiān)聽web的特定事件,隨web應(yīng)用啟動(dòng)而啟動(dòng),只初始化一次。
2. 有什么用
- 攔截器(interceptor):在一個(gè)請求進(jìn)行中的時(shí)候,你想干預(yù)它的進(jìn)展,甚至控制是否終止。這是攔截器做的事。
- 過濾器(Filter):當(dāng)有一堆東西,只希望選擇符合的東西。定義這些要求的工具,就是過濾器。
- 監(jiān)聽器(Listener):一個(gè)事件發(fā)生后,只希望獲取這些事個(gè)事件發(fā)生的細(xì)節(jié),而不去干預(yù)這個(gè)事件的執(zhí)行過程,這就用到監(jiān)聽器
3. 啟動(dòng)順序
監(jiān)聽器 > 過濾器 > 攔截器
4.SpringBoot中的具體實(shí)現(xiàn)
(1) 攔截器
- 攔截器常用有兩種方式實(shí)現(xiàn)
- 實(shí)現(xiàn)HandlerInterceptor接口
- 繼承HandlerInterceptorAdapter 抽象類
- 區(qū)別和聯(lián)系
- HandlerInterceptorAdapter 實(shí)現(xiàn)AsyncHandlerInterceptor接口,AsyncHandlerInterceptor接口 繼承HandlerInterceptor接口.
- AsyncHandlerInterceptor接口多了一個(gè)afterConcurrentHandlingStarted方法
- 具體方法
- preHandle //請求過來之后首先走的方法 return true 繼續(xù)往下執(zhí)行
- postHandle //請求之后返回之前
- afterCompletion //處理完成之后
- afterConcurrentHandlingStarted //如果返回一個(gè)current類型的變量,會啟用一個(gè)新的線程。執(zhí)行完preHandle方法之后立即會調(diào)用afterConcurrentHandlingStarted,然后新線程再以次執(zhí)行preHandle,postHandle,afterCompletion
- 代碼實(shí)現(xiàn)
【注】以下代碼基于springboot2.0
(1)攔截器
MyInterceptor1 繼承 HandlerInterceptorAdapter
MyInterceptor2 實(shí)現(xiàn) HandlerInterceptor接口
public class MyInterceptor1 extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.setAttribute("startTime", System.currentTimeMillis());
System.out.println(">>>>> MyInterceptor1 preHandle >>>>>>>>>>>>>>>>>>>>>>");
return super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
long startTime = (long) request.getAttribute("startTime");
System.out.println("MyInterceptor1 執(zhí)行:" + (System.currentTimeMillis() - startTime));
System.out.println(">>>>> MyInterceptor1 postHandle >>>>>>>>>>>>>>>>>>>>>>");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
request.removeAttribute("startTime");
System.out.println(">>>>> MyInterceptor1 afterCompletion >>>>>>>>>>>>>>>>>>>>>>");
}
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
super.afterConcurrentHandlingStarted(request, response, handler);
System.out.println(">>>>> MyInterceptor1 afterConcurrentHandlingStarted >>>>>>>>>>>>>>>>>>>>>>");
}
}
public class MyInterceptor2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.setAttribute("startTime", System.currentTimeMillis());
System.out.println(">>>>> MyInterceptor2 preHandle >>>>>>>>>>>>>>>>>>>>>>");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
long startTime = (long) request.getAttribute("startTime");
System.out.println("MyInterceptor2 執(zhí)行:" + (System.currentTimeMillis() - startTime));
System.out.println(">>>>> MyInterceptor2 postHandle >>>>>>>>>>>>>>>>>>>>>>");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
request.removeAttribute("startTime");
System.out.println(">>>>> MyInterceptor2 afterCompletion >>>>>>>>>>>>>>>>>>>>>>");
}
}
(2)配置
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/**");
registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/**");
}
}
(3)請求
@RestController
@SpringBootApplication
public class SpringbootInterceptorApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootInterceptorApplication.class, args);
}
@GetMapping(value = "/hello1")
public ResponseEntity<String> hello() throws InterruptedException {
Thread.sleep(500);
return ResponseEntity.ok("HelloWorld");
}
@GetMapping(value = "/hello2")
public StreamingResponseBody hello2() throws InterruptedException {
Thread.sleep(500);
return (OutputStream outputStream) -> {
outputStream.write("success".getBytes());
outputStream.flush();
outputStream.close();
};
}
@GetMapping(value = "/hello3")
public Future<String> hello3() throws InterruptedException {
Thread.sleep(500);
return new AsyncResult<>("Hello");
}
}
(4) 運(yùn)行結(jié)果
-
請求/hello1
>>>>> MyInterceptor1 preHandle >>>>>>>>>>>>>>>>>>>>>> >>>>> MyInterceptor2 preHandle >>>>>>>>>>>>>>>>>>>>>> MyInterceptor2 執(zhí)行:516 >>>>> MyInterceptor2 postHandle >>>>>>>>>>>>>>>>>>>>> MyInterceptor1 執(zhí)行:516 >>>>> MyInterceptor1 postHandle >>>>>>>>>>>>>>>>>>>>> >>>>> MyInterceptor2 afterCompletion >>>>>>>>>>>>>>>> >>>>> MyInterceptor1 afterCompletion >>>>>>>>>>>>>>>>執(zhí)行按preHandle > postHandle > afterCompletion
-
請求/hello2 或 /hello3
>>>>> MyInterceptor1 preHandle >>>>>>>>>>>>>>>>>>>>>> >>>>> MyInterceptor2 preHandle >>>>>>>>>>>>>>>>>>>>>> >>>>> MyInterceptor1 afterConcurrentHandlingStarted >>>>>>>>>>>>>>>>>>>>>> >>>>> MyInterceptor1 preHandle >>>>>>>>>>>>>>>>>>>>>> >>>>> MyInterceptor2 preHandle >>>>>>>>>>>>>>>>>>>>>> MyInterceptor2 執(zhí)行:1 >>>>> MyInterceptor2 postHandle >>>>>>>>>>>>>>>>>>>>>> MyInterceptor1 執(zhí)行:1 >>>>> MyInterceptor1 postHandle >>>>>>>>>>>>>>>>>>>>>> >>>>> MyInterceptor2 afterCompletion >>>>>>>>>>>>>>>>>>>>>> >>>>> MyInterceptor1 afterCompletion >>>>>>>>>>>>>>>>>>>>>>MyInterceptor1 執(zhí)行順序 preHandle > afterConcurrentHandlingStarted > preHandle > postHandle >afterCompletion
MyInterceptor2 執(zhí)行順序 preHandle > preHandle > postHandle > afterCompletion
綜上.對于concurrent類型的返回值,spring會啟用一個(gè)新的線程來處理concurrent類型消息,在新的線程中會重新調(diào)用preHandle方法。
(2) 過濾器
(1) 過濾器
public class MyFilter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println(filterConfig.getInitParameter("initParam"));
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFilter1 >>>>>>>>>>>");
filterChain.doFilter(servletRequest, servletResponse);
}
}
(2) 配置
- 第一種方式
@Bean
public FilterRegistrationBean<MyFilter1> filterRegistrationBean() {
FilterRegistrationBean<MyFilter1> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.addUrlPatterns("/*");//過濾所有
filterRegistrationBean.setFilter(new MyFilter1());
filterRegistrationBean.setOrder(1);
filterRegistrationBean.addInitParameter("initParam", "initOk");
return filterRegistrationBean;
}
- 第二種方式
@Bean
public MyFilter1 myFilter() {
return new MyFilter1();
}
- 第三種方式
@WebFilter("/test/*")
public class MyFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter2");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("DoFilter 2");
}
}
通過@WebFilter("/test/*")注解,首先需要@ServletComponentScan("com.jiuxian")
Filter 全局?jǐn)r截的配置(/*)和 Interceptor(/**)有所區(qū)別需要注意
(3) 監(jiān)聽器
(1) 監(jiān)聽器
public class MyListener1 implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("MyListener1 ... ");
}
}
(2) 配置方式和Filter類似
- 第一種方式
@Bean
public ServletListenerRegistrationBean<MyListener1> registrationBean() {
ServletListenerRegistrationBean<MyListener1> servletListenerRegistrationBean
= new ServletListenerRegistrationBean<>();
servletListenerRegistrationBean.setListener(new MyListener1());
return servletListenerRegistrationBean;
}
- 第二種方式
@Bean
public MyListener1 myListener1() {
return new MyListener1();
}
- 第三種方式
@WebListener
public class MyListener2 implements ServletRequestListener {
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("MyListener2");
}
}
使用@WebListener注解,首先需要@ServletComponentScan("com.jiuxian")
【注】以上代碼基于springboot2.0