Spring拦截器
一、SpringMVC
1.1 请求视图
1.2 核心分发器
DispatcherServlet作为Spring MVC核心分发器。和其他请求驱动的Web框架一样,Spring MVC也是围绕一个 将前端请求分发到相应控制器 的核心Servlet来设计的,这个Servlet就是DispatcherServlet。DispatcherServlet和其他框架中的Servlet不一样的地方在于,它和Spring容器无缝整合在了一起,因此我们可以在Spring MVC中使用Spring所有的特性。
整个请求-响应过程包括处理器(Controller),处理器映射器(HandlerMapping),处理器适配器(HandlerAdaptor),视图解析器(View Resolver),视图(View)等的流转,整个流程如下所示:
主要分为7个步骤:
- 用户请求 -> DispatcherServlet,核心分发器收到请求后自己不进行处理,而是作为统一访问点,进行全局的流程控制。
- DispatcherServlet -> HandlerMapping。HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器对象、多个HandlerInterceptor拦截器对象,拦截器采用一种是链式执行方式),通过这种策略模式,很容易对映射策略进行扩展。
- DispatcherServlet —> HandlerAdapter。HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器。
- HandlerAdapter —> Handler。HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理,并返回一个ModelAndView对象(包含模型数据、逻辑视图名)。
- ModelAndView的逻辑视图名 —> ViewResolver。 ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易扩展其他视图技术。
- View —> 渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,可以支持各种模板渲染引擎。
- 返回响应给用户。
二、 Spring 拦截器
由上可知,HandlerMapping将会把请求映射为HandlerExecutionChain对象,其中HandlerExecutionChain对象包含一个Handler处理器对象、多个HandlerInterceptor拦截器对象,拦截器采用一种是链式执行方式。
2.1 拦截器概念
拦截器是动态拦截action对象,并且提供了一种机制可以使开发者可以定义在一个action执行前后执行的代码,也可以在一个action执行前阻止其执行,并且提供了一种可以在action中可重用部分的方式。在AOP(Aspect-Oriented Programming)中拦截器用户在某个方法或者字段被访问前后可以执行的操作。
2.2 拦截器原理
拦截器Interception的拦截功能是基于Java 动态代理 来实现的。
2.3 拦截器实现
在Spring 框架之中,拦截器的实现主要有两种方法:
- 实现HandlerInterceptor接口;
- 实现WebRequestInterceptor接口 。
本文主要介绍实现HandlerInterceptor接口实现的方法,后续会将实现WebRequestInterceptor接口 方法补充。
2.3.1 HandlerInterceptor 接口
HandlerInterceptor接口定义了3个方法:
- preHandler()
- postHandler()
- afterCompletion()
通过实现上述三个方法对用户的请求进行拦截处理。 下面用来实现session方法就是通过实现preHandler()方法实现的。下面详细介绍3个方法。
- preHandler()方法
/**
* Intercept the execution of a handler. Called after HandlerMapping determined
* an appropriate handler object, but before HandlerAdapter invokes the handler.
* <p>DispatcherServlet processes a handler in an execution chain, consisting
* of any number of interceptors, with the handler itself at the end.
* With this method, each interceptor can decide to abort the execution chain,
* typically sending a HTTP error or writing a custom response.
* <p><strong>Note:</strong> special considerations apply for asynchronous
* request processing. For more details see
* {@link org.springframework.web.servlet.AsyncHandlerInterceptor}.
* @param request current HTTP request
* @param response current HTTP response
* @param handler chosen handler to execute, for type and/or instance evaluation
* @return {@code true} if the execution chain should proceed with the
* next interceptor or the handler itself. Else, DispatcherServlet assumes
* that this interceptor has already dealt with the response itself.
* @throws Exception in case of errors
*/
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
该方法在请求处理之前进行调用。上面提及过Spring MVC 拦截器 链式调用的,即在一个请求中可以同时存在多个Interceptor,每个Interceptor的调用会依据它的声明顺序依次执行。并且拦截器中的preHandler方法是最先执行的,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求做一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔(Boolean)类型 的,当它返回为false时,表示请求结束,后续的Interceptor和控制器(Controller)都不会再执行;当返回值为true时,就会继续调用下一个Interceptor的preHandle方法,如果已经是最后一个Interceptor的时候,就会是调用当前请求的控制器中的方法。
- postHandle()方法
/**
* Intercept the execution of a handler. Called after HandlerAdapter actually
* invoked the handler, but before the DispatcherServlet renders the view.
* Can expose additional model objects to the view via the given ModelAndView.
* <p>DispatcherServlet processes a handler in an execution chain, consisting
* of any number of interceptors, with the handler itself at the end.
* With this method, each interceptor can post-process an execution,
* getting applied in inverse order of the execution chain.
* <p><strong>Note:</strong> special considerations apply for asynchronous
* request processing. For more details see
* {@link org.springframework.web.servlet.AsyncHandlerInterceptor}.
* @param request current HTTP request
* @param response current HTTP response
* @param handler handler (or {@link HandlerMethod}) that started asynchronous
* execution, for type and/or instance examination
* @param modelAndView the {@code ModelAndView} that the handler returned
* (can also be {@code null})
* @throws Exception in case of errors
*/
void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
该方法在只能在当前所属的Interceptor的preHandle方法的返回值为true的时候,才能被调用。postHandle方法在当前请求进行处理之后,也就是在控制器中的方法调用之后执行,但是它会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对控制器处理之后的ModelAndView对象进行操作。postHandle方法被调用的方向跟preHandle是相反的,也就是说,先声明的Interceptor的postHandle方法反而会后执行。
- afterCompletion()方法
/**
* Callback after completion of request processing, that is, after rendering
* the view. Will be called on any outcome of handler execution, thus allows
* for proper resource cleanup.
* <p>Note: Will only be called if this interceptor's {@code preHandle}
* method has successfully completed and returned {@code true}!
* <p>As with the {@code postHandle} method, the method will be invoked on each
* interceptor in the chain in reverse order, so the first interceptor will be
* the last to be invoked.
* <p><strong>Note:</strong> special considerations apply for asynchronous
* request processing. For more details see
* {@link org.springframework.web.servlet.AsyncHandlerInterceptor}.
* @param request current HTTP request
* @param response current HTTP response
* @param handler handler (or {@link HandlerMethod}) that started asynchronous
* execution, for type and/or instance examination
* @param ex exception thrown on handler execution, if any
* @throws Exception in case of errors
*/
void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
afterCompletion()方法同postHandle()方法一样,当Interceptor的preHandler方法返回值为true时,才能被调用。因此,该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行,这个方法的主要作用是用于进行资源清理的工作。