一、拦截器简介
拦截器是spring中的一个重要概念。他被注册到spring,拦截指定规则的请求,基于回调机制执行。一般来说,拦截器只会拦截action请求,这一点与过滤器不同。
下面贴一张spring web请求的执行流程图:
二、拦截器原理
1、拦截器定义
因为拦截器主要是对controller起作用,所以一般在webapp/WEB-INF下的类似spring-web-servlet.xml这样的配置文件中定义拦截器:
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/main/*"/> <bean class="com.chengc.demos.web.demo1.interceptor.FirstInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/main/*"/> <bean class="com.chengc.demos.web.demo1.interceptor.SecondInterceptor"></bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/main/*"/> <bean class="com.chengc.demos.web.demo1.interceptor.ThirdInterceptor"></bean> </mvc:interceptor> </mvc:interceptors> |
2、拦截器创建
Web容器在初始化DispatcherServlet(父类为FrameworkServlet)时,会创建其独有的XmlWebApplicationContext。在初始化该context,FrameworkServlet.configureAndRefreshWebApplicationContext中有一句wac.refresh()时,会在finishBeanFactoryInitialization(beanFactory)方法中调用AbstractHandlerMapping.initApplicationContext方法:
private final List<Object> interceptors = new ArrayList<Object>(); private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>(); protected void initApplicationContext() throws BeansException { // 默认空实现 extendInterceptors(this.interceptors); // 找到定义的interceptor detectMappedInterceptors(this.mappedInterceptors); // 对Interceptors进行初始化 initInterceptors(); } |
- AbstractHandlerMapping.detectMappedInterceptors
protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) { mappedInterceptors.addAll( BeanFactoryUtils.beansOfTypeIncludingAncestors( getApplicationContext(), MappedInterceptor.class, true, false).values()); } |
该方法就会去初始化所有interceptor,调用他们的<clinit>和<init>。
3、拦截器调用
先经过过滤器(机会多所有请求进行过滤),然后才会到拦截器。
- DispatcherServlet会对请求进行doDispatch分发:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { // 传给ViewResolver进行视图解析的对象 ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = processedRequest != request; // 为当前请求准备好HandlerExecutionChain mappedHandler = getHandler(processedRequest, false); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // 为当前请求准备好HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // 调用handler执行链上的interceptor的preHandle方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } try { // 真正调用handler(Controller)处理请求 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); } finally { if (asyncManager.isConcurrentHandlingStarted()) { return; } } applyDefaultViewName(request, mv); // 逆序调用handler执行链上的interceptor的postHandle方法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return; } // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } |
3.1、getHandler
getHandler主要是为当前request创建一个包含了若干路径匹配的interceptor和一个handler(即Controller)的HandlerExecutionChain(执行链)。
- DispatcherServlet.getHandler
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // 这里的handlerMappings就包含了最常用的RequestMappingHandlerMapping for (HandlerMapping hm : this.handlerMappings) { HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; } |
这里看看hm.getHandler,在AbstractHandlerMapping.getHandler方法:
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // 这一步就是根据request的路径找到Controller Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? // 正常的Controller应该是HandlerMethod类 if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } // 获取该Controller的执行链 return getHandlerExecutionChain(handler, request); } |
- AbstractHandlerMethodMapping.getHandlerInternal
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { // 请求的相对路径,比如/main/index String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); // 这一步会真正创建含有目标handler和Method的HandlerMethod对象 return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } |
- AbstractHandlerMapping.getHandlerExecutionChain
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); chain.addInterceptors(getAdaptedInterceptors()); String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); // 将我们前面提到的注册的拦截器读取遍历 for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) { if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { // 如果拦截器的mapping和请求的路径匹配上了,就添加到该Handler的执行链中 chain.addInterceptor(mappedInterceptor.getInterceptor()); } } // 最后得到加上了拦截器的HandlerExecutionChain return chain; } |
这里,HandlerChain已经加入了interceptor:
3.2、getHandlerAdapter
为当前请求创建合适的HandlerAdapter,准备开始执行handler:
一般Controller返回的就是RequestMappingHandlerAdapter。
这就是典型的适配器模式,将某个Controller类适配为RequestMappingHandlerAdapter,后续会反射执行其方法。
3.3、preHandle
这个阶段会调用handler执行链上的interceptor的preHandle方法。
到HandlerExecutionChain.applyPreHandle方法,这里就会调用所有符合该请求的路径映射的interceptor的preHandle方法:
- HandlerExecutionChain.applyPreHandle
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { if (getInterceptors() != null) { // 遍历执行链上的Interceptor for (int i = 0; i < getInterceptors().length; i++) { HandlerInterceptor interceptor = getInterceptors()[i]; // 这里就在调用每个interceptor的preHandle方法了 if (!interceptor.preHandle(request, response, this.handler)) { // interceptor返回true代表给下一个handler, // 返回false代表调用链结束,直接调用handlers.afterCompletion方法. triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; } |
3.4、HandlerAdapter.handle
这个阶段利用handler适配器真正调用handler执行代码逻辑。
我们直接看最关键的类InvocableHandlerMethod:
private Object invoke(Object... args) throws Exception { // 将handler的目标方法设为可访问 ReflectionUtils.makeAccessible(getBridgedMethod()); try { // 对目标handler实例调用目标方法 return getBridgedMethod().invoke(getBean(), args); } } |
可以看到,SpringMVC内是通过反射的方式访问目标handler的方法。
以上的getBridgedMethod和getBean两个方法都来自于该类的父类HandlerMethod,存储了目标handler的Bean和Method。
这里返回的信息可以是ModelAndView, 代表视图路径的字符串,纯信息字符串等。还需要进一步加工处理。经过加工后,都转为ModelAndView。
3.5、postHandle
逆序调用handler执行链上的interceptor的postHandle方法:HandlerExecutionChain.applyPostHandle。
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception { if (getInterceptors() == null) { return; } // 这里就能看到,为什么说是逆序调用postHandle了 for (int i = getInterceptors().length - 1; i >= 0; i--) { HandlerInterceptor interceptor = getInterceptors()[i]; interceptor.postHandle(request, response, this.handler, mv); } } |
3.6、processDispatchResult-视图解析
该步骤主要是处理ModelAndView,ViewResolver解析后得到View。然后将该View处理后,放入response,最终返回给客户端。
- DispatcherServlet.render
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // 请求来源的区域 Locale locale = this.localeResolver.resolveLocale(request); // 给response也用相同区域 response.setLocale(locale); View view; if (mv.isReference()) { // mv指向视图的索引,需要ViewSolver解析 view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException("...") } } else { // ModelAndView本身就包含真实的视图对象 view = mv.getView(); if (view == null) { throw new ServletException("..."); } } // Delegate to the View object for rendering. // 解析视图,放入 try { view.render(mv.getModelInternal(), request, response); } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'", ex); } throw ex; } } |
3.7、triggerAfterCompletion
该步骤作为收尾步骤,主要是逆序执行interceptors的afterCompletion方法:HandlerExecutionChain.triggerAfterCompletion。
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception { if (getInterceptors() == null) { return; } // 逆序遍历执行interceptor的afterCompletion方法 for (int i = this.interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = getInterceptors()[i]; try { interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable ex2) { logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } } |
4、注意事项
拦截器依据器定义顺序执行的,如果想规定其执行顺序则可以使用注解@Order