springboot 过滤器、拦截器、切片(aspect)
本文的环境基础:springboot web模块,aop模块,rest风格
本文的测试功能:对UserController进行拦截,输出每个方法执行的耗时
- spring boot过滤器:过滤器只能取到request,response等信息,不能获取正在过滤的类的信息和方法的信息,不能获取请求参数
过滤器的实现有两种方式:
-
- 通过@Component注解,直接将filter交给spring管理,但是这种方式时过滤所有请求,我没有找到配置过滤路径的地方,欢迎朋友多多指教
1 @Component 2 public class TimeFilter implements Filter { 3 @Override 4 public void init(FilterConfig filterConfig) throws ServletException { 5 System.out.println("TimeFilter : init"); 6 } 7 8 @Override 9 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 10 System.out.println("TimeFilter : doFilter start"); 11 12 Long startTime = System.currentTimeMillis(); 13 14 filterChain.doFilter(servletRequest, servletResponse); 15 16 System.out.println("TimeFilter : 执行耗时 -> " + (System.currentTimeMillis() - startTime) + "ms"); 17 18 System.out.println("TimeFilter : doFilter finish"); 19 } 20 21 @Override 22 public void destroy() { 23 System.out.println("TimeFilter : destroy"); 24 } 25 }


这是过滤器的日志打印,controller千篇一律,这里就不在赘述。
-
- 通过配置类的形式,这种方式可以配置路径
这里对上边的TimeFilter稍作修改,去掉@Component,然后在spring boot的带有@SpringBootApplication注解的主类的目录下级编写自定义WebConfig
1 @Configuration 2 public class WebConfig { 3 4 @Bean 5 public FilterRegistrationBean timeFilter() { 6 FilterRegistrationBean bean = new FilterRegistrationBean(); 7 8 bean.setFilter(new TimeFilter()); 9 10 List<String> urls = new ArrayList<>(); 11 urls.add("/user/*"); 12 bean.setUrlPatterns(urls); 13 14 return bean; 15 } 16 17 }

启动测试,效果类同,只不过多了一个URL的判断
- spring boot拦截器:拦截器可以在过滤器的基础上,可以获取类的信息和方法的信息,但是不能获得请求参数
- 定义拦截器,注意:需要@Component,交给Spring管理
1 @Component 2 public class TimeInterceptor implements HandlerInterceptor { 3 @Override 4 public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { 5 System.out.println("TimeInterceptor : preHandle"); 6 7 httpServletRequest.setAttribute("startTime", System.currentTimeMillis()); 8 9 return true; 10 } 11 12 @Override 13 public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object obj, ModelAndView modelAndView) throws Exception { 14 System.out.println("TimeInterceptor : postHandle start"); 15 16 Long startTime = (Long) httpServletRequest.getAttribute("startTime"); 17 System.out.println("TimeInterceptor : 执行耗时 -> " + (System.currentTimeMillis() - startTime) + "ms"); 18 19 System.out.println("TimeInterceptor : 拦截类名 -> " + ((HandlerMethod) obj).getBean().getClass().getName()); 20 System.out.println("TimeInterceptor : 拦截方法名 -> " + ((HandlerMethod) obj).getMethod().getName()); 21 22 System.out.println("TimeInterceptor : postHandle finish"); 23 } 24 25 @Override 26 public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { 27 System.out.println("TimeInterceptor : afterCompletion"); 28 Long startTime = (Long) httpServletRequest.getAttribute("startTime"); 29 System.out.println("TimeInterceptor : 执行耗时 -> " + (System.currentTimeMillis() - startTime) + "ms"); 30 System.out.println("TimeInterceptor : exception -> " + e);31 } 32 }
- 配置类修改,这是在过滤器的基础上修改的
1 @Configuration 2 public class WebConfig extends WebMvcConfigurerAdapter { 3 4 @Autowired 5 private TimeInterceptor timeInterceptor; 6 7 @Override 8 public void addInterceptors(InterceptorRegistry registry) { 9 registry.addInterceptor(timeInterceptor); 10 } 11 12 @Bean 13 public FilterRegistrationBean timeFilter() { 14 FilterRegistrationBean bean = new FilterRegistrationBean(); 15 16 bean.setFilter(new TimeFilter()); 17 18 List<String> urls = new ArrayList<>(); 19 urls.add("/user/*"); 20 bean.setUrlPatterns(urls); 21 22 return bean; 23 } 24 25 }
- 测试结果,结论:首先进入filter --> 之后进入interceptor的preHandler --> 之后进入controller执行 --> interceptor postHandle --> interceptor afterCompletion --> filter,执行完毕
- 定义拦截器,注意:需要@Component,交给Spring管理
当无异常抛出时,postHandle 和afterCompletion都会执行,当有异常抛出时,postHandle 不会执行,但是afterCompletion仍会执行,我们可以在这里对异常进行处理

- spring boot aspect:切点在过滤器和拦截器的基础上,还可以获取请求参数
- 定义切点,关于切点的定义,可以参考 https://docs.spring.io/spring/docs/4.3.14.RELEASE/spring-framework-reference/htmlsingle/#aop-pointcuts
1 @Component 2 @Aspect 3 public class TimeAspect { 4 5 @Around("execution(* com.mright.platform.controller.UserController.*(..))") 6 public Object handleControllerMethod(ProceedingJoinPoint point) throws Throwable { 7 System.out.println("TimeAspect : start"); 8 Long startTime = System.currentTimeMillis(); 9 10 Object[] args = point.getArgs(); 11 Arrays.stream(args).forEach(arg -> { 12 System.out.println("TimeAspect : 参数 -> " + arg); 13 }); 14 15 Object object = point.proceed(); 16 17 System.out.println("TimeAspect : finish"); 18 19 System.out.println("TimeAspect : 执行耗时 -> " + (System.currentTimeMillis() - startTime) + "ms"); 20 return object; 21 } 22 23 }
- 运行结果如下,执行顺序显而易见,filter --> interceptor --> aspect
- 定义切点,关于切点的定义,可以参考 https://docs.spring.io/spring/docs/4.3.14.RELEASE/spring-framework-reference/htmlsingle/#aop-pointcuts


浙公网安备 33010602011771号