springboot三種攔截器的使用與比較
springboot中有三種攔截器可供選擇:filter、interceptort和aop。本文主要討論三種攔截器的使用場景與使用方式。
下文中的舉例功能是計算每個請求的從開始到結束的時間,例子來源是慕課網。
一、filter
特點:可以獲取原始的ServletRequest,但無法獲取具體方法
實現:
1.繼承javax.servlet.Filter類,
2.@Component註解將其註入到框架中
3.實現其中的dofilter方法,所有的請求都會經過該方法,可以在此計算出每個請求的耗時,代碼如下:
1 package com.zzy.web.filter; 2 3 importjava.io.IOException; 4 import java.util.Date; 5 6 import javax.servlet.Filter; 7 import javax.servlet.FilterChain; 8 import javax.servlet.FilterConfig; 9 import javax.servlet.ServletException; 10 import javax.servlet.ServletRequest; 11 import javax.servlet.ServletResponse; 12 13 import org.springframework.stereotype.Component;14 15 @Component 16 public class TimeFilter implements Filter{ 17 18 @Override 19 public void init(FilterConfig filterConfig) throws ServletException { 20 // TODO Auto-generated method stub 21 System.out.println("filter init"); 22 23 } 24 25 @Override 26 publicvoid doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 27 throws IOException, ServletException { 28 // TODO Auto-generated method stub 29 Long startTime = new Date().getTime(); 30 System.out.println("filter 請求開始時間:"+ startTime); 31 chain.doFilter(request, response); 32 Long endTime = new Date().getTime(); 33 System.out.println("filter 請求結束時間:" + endTime +",請求耗時:" + (endTime - startTime)); 34 35 } 36 37 @Override 38 public void destroy() { 39 // TODO Auto-generated method stub 40 41 } 42 43 }
註:如果有的框架沒有@Component 這個註解,可以自己寫一個配置類,在該類中指定過濾器,而且還可以指定過濾的url,配置類如下:
1 package com.zzy.web.config; 2 3 import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; 4 5 import java.util.ArrayList; 6 import java.util.List; 7 8 import org.springframework.beans.factory.annotation.Autowired; 9 import org.springframework.boot.web.servlet.FilterRegistrationBean; 10 import org.springframework.context.annotation.Bean; 11 import org.springframework.context.annotation.Configuration; 12 import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 13 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 14 15 import com.zzy.web.filter.TimeFilter; 16 import com.zzy.web.interceptor.TimeInterceptor; 17 18 @Configuration 19 public class WebConfig extends WebMvcConfigurerAdapter { 20 21 @Autowired 22 private TimeInterceptor timeInterceptor; 23 24 // @Override 25 // public void addInterceptors(InterceptorRegistry registry) { 26 // // TODO Auto-generated method stub 27 // registry.addInterceptor(timeInterceptor); 28 // } 29 30 @Bean 31 public FilterRegistrationBean timeFilter() { 32 FilterRegistrationBean registrationBean = new FilterRegistrationBean(); 33 TimeFilter timeFilter = new TimeFilter(); 34 registrationBean.setFilter(timeFilter); 35 List<String> urls = new ArrayList<>(); 36 urls.add("/user/*"); 37 registrationBean.setUrlPatterns(urls); 38 return registrationBean; 39 } 40 41 }
二、interceptor
特點:可以獲取到原始的request和請求的方法,但無法獲取方法的具體參數的值。
實現:
1.繼承HandlerInterceptor接口
2.請求前的邏輯寫在prehandle(請求前調用)
3.請求後的邏輯寫在posthandle(請求成功後調用,失敗則不調用)
4.請求後,不管成功失敗都會調用aftercompletion。
5.intceptor方式繼承了之後還沒起作用,還需要在配置類裏面加一下,把剛聲明的攔截器註冊一下。
代碼示例:
1 package com.zzy.web.interceptor; 2 3 import java.util.Arrays; 4 import java.util.Date; 5 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 9 import org.springframework.stereotype.Component; 10 import org.springframework.web.method.HandlerMethod; 11 import org.springframework.web.servlet.HandlerInterceptor; 12 import org.springframework.web.servlet.ModelAndView; 13 @Component 14 public class TimeInterceptor implements HandlerInterceptor { 15 16 @Override 17 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 18 throws Exception { 19 // TODO Auto-generated method stub 20 System.out.println("interceptor 執行preHandle"); 21 22 request.setAttribute("startTime", new Date().getTime()); 23 return true; 24 } 25 26 @Override 27 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, 28 ModelAndView modelAndView) throws Exception { 29 // TODO Auto-generated method stub 30 Long startTime = Long.parseLong(request.getAttribute("startTime").toString()); 31 Long endTime = new Date().getTime(); 32 System.out.println("interceptor 執行postHandle"); 33 System.out.println("interceptor 請求類:"+((HandlerMethod)handler).getBean().getClass().getName()); 34 System.out.println("interceptor 請求方法:"+((HandlerMethod)handler).getMethod()); 35 // System.out.println("interceptor 請求參數:"); 36 // Arrays.asList(((HandlerMethod)handler).getMethodParameters()).stream().forEach(arg->System.out.println(arg)); 37 System.out.println("interceptor 請求耗時:" + (endTime - startTime)); 38 39 } 40 41 @Override 42 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) 43 throws Exception { 44 // TODO Auto-generated method stub 45 Long startTime = Long.parseLong(request.getAttribute("startTime").toString()); 46 Long endTime = new Date().getTime(); 47 System.out.println("interceptor 執行afterCompletion"); 48 System.out.println("interceptor 請求類:"+((HandlerMethod)handler).getBean().getClass().getName()); 49 System.out.println("interceptor 請求方法:"+((HandlerMethod)handler).getMethod()); 50 System.out.println("interceptor 請求耗時:" + (endTime - startTime)); 51 System.out.println("interceptor 請求異常:" + ex); 52 53 } 54 55 }
配置類如下:
1 package com.zzy.web.config; 2 3 import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; 4 5 import java.util.ArrayList; 6 import java.util.List; 7 8 import org.springframework.beans.factory.annotation.Autowired; 9 import org.springframework.boot.web.servlet.FilterRegistrationBean; 10 import org.springframework.context.annotation.Bean; 11 import org.springframework.context.annotation.Configuration; 12 import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 13 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 14 15 import com.zzy.web.filter.TimeFilter; 16 import com.zzy.web.interceptor.TimeInterceptor; 17 18 @Configuration 19 public class WebConfig extends WebMvcConfigurerAdapter { 20 21 @Autowired 22 private TimeInterceptor timeInterceptor; 23 24 @Override 25 public void addInterceptors(InterceptorRegistry registry) { 26 // TODO Auto-generated method stub 27 registry.addInterceptor(timeInterceptor); 28 } 29 30 31 }
三、aop
特點:能拿到方法和具體參數的值,但是拿不到原始的servletrequest的信息。
實現:
1.使用@aspect註解
2.@execution聲明切面,聲明切面的語法可參考官網https://docs.spring.io/spring/docs/4.3.18.RELEASE/spring-framework-reference/htmlsingle/#aop-pointcuts
3.使用@Around(方法前和方法後),@Before(方法前)或@After(方法後)
以下為@Around舉例,代碼如下:
1 package com.zzy.web.aspect; 2 3 import java.util.Date; 4 5 import org.aspectj.lang.ProceedingJoinPoint; 6 import org.aspectj.lang.annotation.Around; 7 import org.aspectj.lang.annotation.Aspect; 8 import org.codehaus.jackson.map.ObjectMapper; 9 import org.springframework.stereotype.Component; 10 11 @Aspect 12 @Component 13 public class TimeAspect { 14 15 @Around("execution(* com.zzy.web.controller.UserController.*(..))") 16 public Object test(ProceedingJoinPoint pjp) throws Throwable { 17 Long startTime = new Date().getTime(); 18 Object[] args = pjp.getArgs(); 19 for (Object arg : args) { 20 System.out.println("aspect 參數:" + arg); 21 } 22 Object object = pjp.proceed(); 23 System.out.println("aspect 請求耗時:" + (new Date().getTime() - startTime)); 24 System.out.println("aspect 請求結果:" + new ObjectMapper().writeValueAsString(object)); 25 26 return object; 27 28 } 29 }
springboot三種攔截器的使用與比較