SpringMVC拦截器源码解析

 前言:提到拦截器,我们一定会想到Spring Aop。在看SpringMVC源码以前,一直以为SpringMVC的拦截器是用Spring Aop的动态代理来实现,并且也很困惑,如果用动态代理如何实现拦截器?这里就不介绍Spring Aop实现拦截器的方式,剖析SpringMVC 拦截器实现的细节。

    SpringMVC拦截器也是Aop(面向切面)思想构建,但不是SpringAop动态代理实现的,主要采用责任链和适配器的设计模式来实现,直接嵌入到SpringMVC入口代码里面。

    涉及到设计模式,有利于对代码的理解

        责任链模式:https://segmentfault.com/a/1190000012079496

        适配器模式:https://www.cnblogs.com/V1haoge/p/6479118.html

一、拦截器的接口类结构

SpringMVC拦截器源码解析_第1张图片

拦截器的顶级接口为HandleInterceptor,提供三个接口,分别是preHandle(请求前)、postHandle(请求提交)、afterCompletion(请求完成后拦截)

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.method.HandlerMethod;
/**
*  拦截器顶级接口
*/
public interface HandlerInterceptor {

    //请求前拦截
	boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception;

    //提交请求拦截
	void postHandle(
			HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
			throws Exception;
    //请求完成后拦截
	void afterCompletion(
			HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception;

}

而我们通常使用的是HandlerInterceptorAdapter(拦截器适配器),运用接口适配器模式。在实际运用中,接口中可以定义了很多方法,子类可能实现几个方法,接口适配器模式就起到了作用。

package org.springframework.web.servlet.handler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		return true;
	}
	@Override
	public void postHandle(
			HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
			throws Exception {
	}
	@Override
	public void afterCompletion(
			HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
	}
	/**
	 * This implementation is empty.
     * 来自实现AsyncHandlerInterceptor 的方法
	 */
	@Override
	public void afterConcurrentHandlingStarted(
			HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
	}

}

二、拦截器源码运行的调用流程

    1. HandlerMapping初始化

了解到SpringMVC拦截器接口HandlerInterceptorAdapter,我们再进入SpringMVC请求入口org.springframework.web.servlet.DispatcherServlet,拦截器运作工作流程由此展开。DispatcherServlet作为控制中心,拦截器就嵌入在入口方法中doDispatch中。SpringMVC又是如何将定义的拦截器加入进去呢?


	/**
	 * 完成Servlet一系列初始化工作,包括视图解析器、处理器映射器、处理器适配器、主题解析器...
	 */
	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
        // 初始化RequestMapping,拦截器是作用在RequestMapping
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

 

初始化RequestMapping的时候,获取到RequestMapping的集合,因为拦截器作用在单个RequestMapping,来实现拦截器链。这里就不详细介绍RequestMapping的获取。

    2. DispatcherServlet执行调用,doService作为Servlet主要执行者,通过调用doDispatch来真正执行请求处理

在initStrategies(ApplicationContext context)完成初始化准备工作后,来正式进入DispatcherServlet请求进入的处理过程。DispatcherServlet基于Servlet开发,它的执行方式是 doService(HttpServletRequest request, HttpServletResponse response) 

   /**
    *  doService做了一部分请求准备预处理的工作, 而实际处理的工作调用doDispatch(request, response)
    */
	@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (logger.isDebugEnabled()) {
			String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
			logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
					" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
		}

		// 对请求属性快照的保持和存储后的使用,
		Map attributesSnapshot = null;
		if (WebUtils.isIncludeRequest(request)) {
			attributesSnapshot = new HashMap();
			Enumeration attrNames = request.getAttributeNames();
			while (attrNames.hasMoreElements()) {
				String attrName = (String) attrNames.nextElement();
				if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
					attributesSnapshot.put(attrName, request.getAttribute(attrName));
				}
			}
		}

		//对SpringMVC框架中处理器Handle和视图渲染,提前做准备工作
		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
        // FlashMap是对重定向的参数传递的处理
		FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
		if (inputFlashMap != null) {
			request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
		}
		request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
		request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

		try {
           //***请求的实际处理逻辑***-----进入方法
			doDispatch(request, response);
		}
		finally {
			if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
				// Restore the original attribute snapshot, in case of an include.
				if (attributesSnapshot != null) {
					restoreAttributesAfterInclude(request, attributesSnapshot);
				}
			}
		}
	}

    3. doDispatch中完成拦截器的添加和拦截器拦截处理

 doService做了一部分请求准备预处理的工作,包括请求中设置处理器和视图的属性,作用于后续处理器的运作和视图渲染, 而实际请求逻辑处理的工作调用doDispatch(request, response),也是我们需要重点跟进的代码。或许大家初次看doDispatch方法中的代码,还不知道拦截器在哪里运作。

处理流程是:

  1.     通过getHandler(HttpServletRequest request)获取到HandlerExecutionChain处理器执行链,将拦截器注入到HandlerExecutionChain属性
  2.   分别调用HandlerExecutionChain的三个方法,applyPreHandle、applyPostHandle、triggerAfterCompletion,实现前置拦截/请求提交拦截和请求完成后拦截。使用责任链的设计模式,实际调用的是HandleInterceptor的三个接口,分别对应preHandle、postHandle、afterCompletion
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		try {
			ModelAndView mv = null;
			Exception dispatchException = null;
			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);
				//***获取到请求执行链,拦截器的添加在里面完成***---进入方法
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}
				// 获取到相应处理器适配器
				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 (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
                //1.请求前拦截处理---进入方法细看(责任链模式,调用拦截器链的执行)
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}
				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
                //2.请求提交的拦截处理---进入方法细看(责任链模式,调用拦截器链的执行)
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
            // 3.请求结果视图渲染完成后,调用mappedHandler.triggerAfterCompletion(),实现请求完成后拦截
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

 

三、结合责任链设计在拦截器中的运用

    责任链模式的定义:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系, 将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止。

分析 1、如何将拦截器添加到HandlerExecutionChain中

    首先遍历HandlerMappings集合,HandlerMappings是在initHandlerMappings(context)初始化得到。根据request查找到相应 HandlerMapping的HandlerExecutionChain。

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //遍历处理器映射器集合,找到相应请求的处理器映射器
		for (HandlerMapping hm : this.handlerMappings) {
			if (logger.isTraceEnabled()) {
				logger.trace(
						"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
			}
            //***请求匹配到映射器,并返回HandlerExecutionChain***---进入方法细看
            //----拦截器的添加在方法里面完成
			HandlerExecutionChain handler = hm.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
		return null;
	}
@Override
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		Object handler = getHandlerInternal(request);
		if (handler == null) {
			handler = getDefaultHandler();
		}
		if (handler == null) {
			return null;
		}
		// Bean name or resolved handler?
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = getApplicationContext().getBean(handlerName);
		}
        //***获取HandlerExecutionChain,拦截器的添加 ***---进一步跟进代码
		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
		if (CorsUtils.isCorsRequest(request)) {
			CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}
		return executionChain;
	}
/**
 * 走到这里,才真正看到了HandlerExecutionChain的创建和拦截器的添加
 */
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        //获取到HandlerExecutionChain 
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        //遍历拦截器,adaptedInterceptors也是在initHandlerMapping初始化得到
		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
			if (interceptor instanceof MappedInterceptor) {
				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                    //将拦截器添加
					chain.addInterceptor(mappedInterceptor.getInterceptor());
				}
			}
			else {
				chain.addInterceptor(interceptor);
			}
		}
		return chain;
	}

分析2、如何执行多个拦截器,通过责任链模式

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				if (!interceptor.preHandle(request, response, this.handler)) {
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}
/**
	 * Apply postHandle methods of registered interceptors.
	 */
	void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = interceptors.length - 1; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				interceptor.postHandle(request, response, this.handler, mv);
			}
		}
	}
/**
	 * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
	 * Will just invoke afterCompletion for all interceptors whose preHandle invocation
	 * has successfully completed and returned true.
	 */
	void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
			throws Exception {

		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = this.interceptorIndex; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				try {
					interceptor.afterCompletion(request, response, this.handler, ex);
				}
				catch (Throwable ex2) {
					logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
				}
			}
		}
	}

你可能感兴趣的:(Springmvc,源码分析,SpringMVC,源码分析)