详解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