详解java中spring里的三大拦截器
Filter
新建TimeFilter
@Component publicclassTimeFilterimplementsFilter{ @Override publicvoidinit(FilterConfigfilterConfig)throwsServletException{ System.out.println("timefilterinit"); } @Override publicvoiddoFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainfilterChain)throwsIOException,ServletException{ System.out.println("timefilterstart"); longstartTime=System.currentTimeMillis(); filterChain.doFilter(servletRequest,servletResponse); longendTime=System.currentTimeMillis(); System.out.println("timefilterconsume"+(endTime-startTime)+"ms"); System.out.println("timefilterend"); } @Override publicvoiddestroy(){ System.out.println("timefilterinit"); } }
启动服务器,在浏览器输入:http://localhost:8080/hello?name=tom
可以在控制台输出如下结果:
timefilterstart
name:tom
timefilterconsume3ms
timefilterend
可以看到,filter先执行,再到真正执行HelloController.sayHello()方法。
通过TimeFilter.doFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainfilterChain)方法的参数可以看出,我们只能得到原始的request和response对象,不能得到这个请求被哪个Controller以及哪个方法处理了,使用Interceptor就可以获得这些信息。
Interceptor
新建TimeInterceptor
@Component publicclassTimeInterceptorextendsHandlerInterceptorAdapter{ privatefinalNamedThreadLocalstartTimeThreadLocal=newNamedThreadLocal<>("startTimeThreadLocal"); @Override publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{ System.out.println("timeinterceptorpreHandle"); HandlerMethodhandlerMethod=(HandlerMethod)handler; //获取处理当前请求的handler信息 System.out.println("handler类:"+handlerMethod.getBeanType().getName()); System.out.println("handler方法:"+handlerMethod.getMethod().getName()); MethodParameter[]methodParameters=handlerMethod.getMethodParameters(); for(MethodParametermethodParameter:methodParameters){ StringparameterName=methodParameter.getParameterName(); //只能获取参数的名称,不能获取到参数的值 //System.out.println("parameterName:"+parameterName); } //把当前时间放入threadLocal startTimeThreadLocal.set(System.currentTimeMillis()); returntrue; } @Override publicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,ModelAndViewmodelAndView)throwsException{ System.out.println("timeinterceptorpostHandle"); } @Override publicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex)throwsException{ //从threadLocal取出刚才存入的startTime LongstartTime=startTimeThreadLocal.get(); longendTime=System.currentTimeMillis(); System.out.println("timeinterceptorconsume"+(endTime-startTime)+"ms"); System.out.println("timeinterceptorafterCompletion"); } }
注册TimeInterceptor
把TimeInterceptor注入spring容器
@Configuration publicclassWebConfigextendsWebMvcConfigurerAdapter{ @Autowired privateTimeInterceptortimeInterceptor; @Override publicvoidaddInterceptors(InterceptorRegistryregistry){ registry.addInterceptor(timeInterceptor); } }
启动服务器,在浏览器输入:http://localhost:8080/hello?name=tom
可以在控制台输出如下结果:
timefilterstart timeinterceptorpreHandle handler类:com.nextyu.demo.web.controller.HelloController handler方法:sayHello name:tom timeinterceptorpostHandle timeinterceptorconsume40ms timeinterceptorafterCompletion timefilterconsume51ms timefilterend
可以看到,filter先于interceptor执行,再到真正执行HelloController.sayHello()方法。通过interceptor方法上的handler参数,我们就可以得到这个请求被哪个Controller以及哪个方法处理了。但是不能直接获取到这个方法上的参数值(在这里就是HelloController.sayHello(Stringname)方法参数name的值),通过Aspect就可以获取到。
Aspcet
新建TimeAspect
@Aspect @Component publicclassTimeAspect{ @Around("execution(*com.nextyu.demo.web.controller.*.*(..))") publicObjecthandleControllerMethod(ProceedingJoinPointpjp)throwsThrowable{ System.out.println("timeaspectstart"); Object[]args=pjp.getArgs(); for(Objectarg:args){ System.out.println("argis"+arg); } longstartTime=System.currentTimeMillis(); Objectobject=pjp.proceed(); longendTime=System.currentTimeMillis(); System.out.println("timeaspectconsume"+(endTime-startTime)+"ms"); System.out.println("timeaspectend"); returnobject; } }
启动服务器,在浏览器输入:http://localhost:8080/hello?name=tom
可以在控制台输出如下结果:
timefilterstart timeinterceptorpreHandle handler类:com.nextyu.demo.web.controller.HelloController handler方法:sayHello timeaspectstart argistom name:tom timeaspectconsume0ms timeaspectend timeinterceptorpostHandle timeinterceptorconsume2ms timeinterceptorafterCompletion timefilterconsume4ms timefilterend
可以看到,filter先执行,再到interceptor执行,再到aspect执行,再到真正执行HelloController.sayHello()方法。
我们也获取到了HelloController.sayHello(Stringname)方法参数name的值。
请求拦截过程图
graphTD httprequest-->filter filter-->interceptor interceptor-->aspect aspect-->controller