是什么
HandlerInterceptor拦截的是请求,是springMVC项目中的拦截器,它拦截的目标是请求的地址。也就是说,它可以对请求进行拦截处理,所有实现了HandlerInterceptor,并且进行了配置的的类,都有这个能力,它的原理,和Filter很相似,我们一起来看一下具体代码是怎么回事。
来个例子
首先我们自己建一个springboot的项目,然后写两个测试接口:
@RequestMapping() @Controller @ResponseBody public class TestController { @GetMapping("/test") public void test(){ System.out.println("test"); } @GetMapping("/login/test") public void login(){ TestController.class.getClassLoader(); System.out.println("login test"); }
然后再写两个拦截器:
public class UserIntercepter implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("MyInterceptor 拦截器执行preHandle()方法"); return true; } // 当preHandle方法返回值为true的时候才会执行。 // 重写postHandle方法,在请求完成后执行。 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle执行了"); } // 当preHandle方法返回值为true的时候才会执行。 // 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面); @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion执行了"); } }
第二个:
public class LoginIntercepter implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("LoginIntercepter 拦截器执行preHandle()方法"); return true; } // 当preHandle方法返回值为true的时候才会执行。 // 重写postHandle方法,在请求完成后执行。 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("LoginIntercepter的postHandle执行了"); } // 当preHandle方法返回值为true的时候才会执行。 // 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面); @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("LoginIntercepter的afterCompletion执行了"); } }
拦截器写好了,还需要写一个配置类把拦截器配置上才可以起效
@Configuration public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new UserIntercepter()) .addPathPatterns("/**") ; //拦截所有的路径 registry.addInterceptor(new LoginIntercepter()) .addPathPatterns("/login/**"); } }
什么时候加载的
一般来说,我们的类想要被spring容器管理,需要给类加上@Service,@Componet之类的注解,但是很明显,我们的两个拦截器是没有加的,但是我们的配置类加了,所以我们给配置类打个断点,然后启动项目,看看发生了什么。
断点停下来之后,往上找,看看是哪里在调用:
注意这是倒着网上找的,所以,很明显,在程序启动的时候,我们自己写的拦截器就被spring的容器管理起来了。
什么时候起效的
那么这玩意儿咋起效呢?这就得看一下我们的org.springframework.web.servlet.DispatcherServlet
中的doDispatch(HttpServletRequest request, HttpServletResponse response)
方法。
调用接口-找到拦截器
首先我们调用一下test接口,然后看一下org.springframework.web.servlet.DispatcherServlet
中的doDispatch(HttpServletRequest request, HttpServletResponse response)
断点,可以看到,走到这一步的时候,其实拦截器已经被找到了,我们有两个拦截器,这里加载了全部拦截的那一个。
然后我们进入getHandler(HttpServletRequest request)
看看是怎么找到这个拦截器的。
可以看到,拦截器都保存在这个handlerMappings
中的RequestMappingHandlerMapping
中,然后mapping.getHandler(request)
就负责找到接口对应的servlet和interceptors。
这个handlerMappings会在有第一次接口调用的时候被初始化,代码在这里:
看一下具体是怎么拿的:
注意一下,这里并不需要从头初始化,知识根据类型,从ApplicationContext,也就是容器里请求拿出来就可以。
调用接口-拦截器起效
现在我们已经有了对应的servlet和interceptors,那它如何起效呢,先来整体看一下:
依次执行各个拦截器的preHandle
其他的也大致相同。
总结
大致流程总结一下就是,我们编写的拦截器,会通过我们的配置类,被spring的容器管理起来,也就是程序启动时就被加载到容器中,然后当我们需要使用的时候,DispatchServlet初始化的时候,拦截器会被加载到它的属性private List<HandlerMapping> handlerMappings;
中,注意,这是个list,我们的接口和拦截器都只属于其中的一个,就是RequestMappingHandlerMapping
这个属性,找到对应的处理器之后,就按照流程执行了
以上,其实就HandlerInterceptor