SpringMvc源码分析(三) 请求执行过程之获取MethodHandler

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

1.请求是如何关联到DispatcherServlet的  

 DispatcherServlet是Servlet的实现遵循Servlet生命周期的规则。

Servlet的生命周期即其出生到死亡的过程中分别会调用Servlet里的以下方法

加载和实例化可以参考SpringMvc源码分析一

init方法初始化在整个 servlet 生命周期中init() 方法只会被调用一次即服务器启动后第一次请求时会调用一次后续请求不再调用。

service方法每次请求都会调用该service方法。

destory方法重启加载或者重启容器时会调用该方法。

      当前端向Tomcat服务器发起请求时被Tomcat容器里管理的DispatcherServlet接收到Tomcat监听到的请求信息第一次调用init方法初始化然后再调用Service方法。

以下是DispatcherServlet的继承实现树

      先分析init方法根据DispatcherServlet类的继承实现树其实际调用的时HttpServletBean里的init方法

	public final void init() throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing servlet '" + getServletName() + "'");
		}

		// Set bean properties from init parameters.
		PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
		if (!pvs.isEmpty()) {
			try {
				BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
				ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
				bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
				initBeanWrapper(bw);
				bw.setPropertyValues(pvs, true);
			}
			catch (BeansException ex) {
				if (logger.isErrorEnabled()) {
					logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
				}
				throw ex;
			}
		}
        //重点关注此处
		// Let subclasses do whatever initialization they like.
		initServletBean();

		if (logger.isDebugEnabled()) {
			logger.debug("Servlet '" + getServletName() + "' configured successfully");
		}
	}

       在该方法中initServletBean方法是一个未实现的方法。其实际实现的方法在FrameworkServlet类的initServletBean中

	@Override
	protected final void initServletBean() throws ServletException {
		getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
		if (this.logger.isInfoEnabled()) {
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
            //重点关注此处
			this.webApplicationContext = initWebApplicationContext();
			initFrameworkServlet();
		}
		catch (ServletException | RuntimeException ex) {
			this.logger.error("Context initialization failed", ex);
			throw ex;
		}

		if (this.logger.isInfoEnabled()) {
			long elapsedTime = System.currentTimeMillis() - startTime;
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
					elapsedTime + " ms");
		}
	}

 分析FrameworkServlet类里的initWebApplicationContext方法。

	protected WebApplicationContext initWebApplicationContext() {
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		if (this.webApplicationContext != null) {
			// A context instance was injected at construction time -> use it
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
					// The context has not yet been refreshed -> provide services such as
					// setting the parent context, setting the application context id, etc
					if (cwac.getParent() == null) {
						// The context instance was injected without an explicit parent -> set
						// the root application context (if any; may be null) as the parent
						cwac.setParent(rootContext);
					}
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		if (wac == null) {
			// No context instance was injected at construction time -> see if one
			// has been registered in the servlet context. If one exists, it is assumed
			// that the parent context (if any) has already been set and that the
			// user has performed any initialization such as setting the context id
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			// No context instance is defined for this servlet -> create a local one
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			// Either the context is not a ConfigurableApplicationContext with refresh
			// support or the context injected at construction time had already been
			// refreshed -> trigger initial onRefresh manually here.
            //重点关注此处
			onRefresh(wac);
		}

		if (this.publishContext) {
			// Publish the context as a servlet context attribute.
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
						"' as ServletContext attribute with name [" + attrName + "]");
			}
		}

		return wac;
	}

上面源码中的onRefresh最后调用的是DispatcherServlet类里的initStrategies方法。

	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}
	protected void initStrategies(ApplicationContext context) {
        //初始化文件处理解析器
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
        //对DispatcherServlet类中的handlerMappings处理器映射属性赋值
		initHandlerMappings(context);
        //对DispatcherServlet类中的handlerAdapters适配器映射属性赋值
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
        //初始化视图解析器
		initViewResolvers(context);
		initFlashMapManager(context);
	}

     观察DispatcherServlet继承树里的结构 其继承了HttpServlet类调用DispatcherServlet对象的Service方法时实际调用的是HttpServlet类里的service方法。 

 在HttpServlet类里的代码中我们可以看到根据不同的前端请求方式比如GET,POST等不同的请求方式执行了不同的方法。

    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException
    {
        HttpServletRequest  request;
        HttpServletResponse response;
        
        if (!(req instanceof HttpServletRequest &&
                res instanceof HttpServletResponse)) {
            throw new ServletException("non-HTTP request or response");
        }

        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;

        service(request, response);
    }
}
    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
            
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
            
        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }

因为是DispatcherServlet类型的对象调用的service方法而FrameworkServlet类、HttpServlet类都实现了doGet、doPost等方法根据动态绑定机制的原理因为FrameworkServlet比HttpServlet类的继承管理离DispatcherServlet更近所以调用的是FrameworkServlet里的doGet,doPost方法。在这些方法内部中我们发现都调用了processRequest方法

	@Override
	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

继续分析FrameworkServlet类中的processRequest方法。

	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
        //开始时间
		long startTime = System.currentTimeMillis();
		Throwable failureCause = null;
        //获取上一个LocalContext,这里叫上一个
        //是因为此方法是从ThreadLocal中获取的获取当前线程的LocaleContext
		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
        //构建一个本地国际化上下文SimpleLocaleContext
		LocaleContext localeContext = buildLocaleContext(request);
        //获取当前绑定到线程的RequestAttributes
		RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        // 构建ServletRequestAttributes
		ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
        //将localeContext和requestAttributes放入当前线程中
		initContextHolders(request, localeContext, requestAttributes);

		try {
            //核心处理
			doService(request, response);
		}
		catch (ServletException | IOException ex) {
			failureCause = ex;
			throw ex;
		}
		catch (Throwable ex) {
			failureCause = ex;
			throw new NestedServletException("Request processing failed", ex);
		}

		finally {
			resetContextHolders(request, previousLocaleContext, previousAttributes);
			if (requestAttributes != null) {
				requestAttributes.requestCompleted();
			}

			if (logger.isDebugEnabled()) {
				if (failureCause != null) {
					this.logger.debug("Could not complete request", failureCause);
				}
				else {
					if (asyncManager.isConcurrentHandlingStarted()) {
						logger.debug("Leaving response open for concurrent processing");
					}
					else {
						this.logger.debug("Successfully completed request");
					}
				}
			}
            //发布事件
			publishRequestHandledEvent(request, response, startTime, failureCause);
		}
	}

在FrameworkServlet类中的该方法中调用了doService方法但是DispatcherServlet类中存在doService方法所以调用的是DispatcherServlet类的的doService方法。

	@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) + "]");
		}
        // 保留请求属性的快照以防出现include
		// 能够在include之后恢复原始属性
		// Keep a snapshot of the request attributes in case of an include,
		// to be able to restore the original attributes after the include.
		Map<String, Object> 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));
				}
			}
		}

		// Make framework objects available to handlers and view objects.
		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());

		if (this.flashMapManager != null) {
			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);
				}
			}
		}
	}

 在上面的源码中需要重点关注doDispatch(request, response)以下是分发方法的源码

在该源码中需要关注以下代码

1.getHandler(processedRequest)   获取处理器链的方法

2.getHandlerAdapter(mappedHandler.getHandler())  获取处理器链封装到适配器

3.mappedHandler.applyPreHandle(processedRequest, response) 请求前预处理

4.ha.handle(processedRequest, response, mappedHandler.getHandler())调用适配器的处理方法

5.mappedHandler.applyPostHandle(processedRequest, response, mv)请求执行后处理

6.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)

   请求后置处理

2.请求是如何获取到处理器执行链

本文分析的是获取处理器的过程所以主要讲述方法一和方法二

	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 {
                //检查当前请求是不是一个文件上传的请求
                //是返回MultipartHttpServletRequest类型对象
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);
                // 确认当前请求的处理器根据不同的请求返回不同的处理器
				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}
                //获取当前处理器的适配器
				// Determine handler adapter for the current request.
				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;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

				applyDefaultViewName(processedRequest, mv);
				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);
			}
			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);
				}
			}
		}
	}

2.1获取处理器执行链分析 

方法一getHandler获取处理器

找到DispatcherServlet类里的getHandler方法代码中handlerMappings属性中获取到HandlerMapping类型的对象。实际上该对象是RequestMappingHandlerMapping类的一个实例。

注意为什么是有7种映射但是返回的是RequestMappingHandlerMapping的映射就不分析了。

因为这些方法一个一个分析比较麻烦。只需要知道通过debug最终返回的是一个RequestMappingHandlerMapping类型的对象就可以了。因为需要分析的类太多了。

获取到RequestMappingHandlerMapping类型的对象后该对象的执行逻辑hm.getHandler方法来获取方法执行器链

	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping hm : this.handlerMappings) {
				if (logger.isTraceEnabled()) {
					logger.trace(
							"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
				}
				HandlerExecutionChain handler = hm.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

 HandlerMapping里的getHandler是一个未实现的方法实际实现的方法在AbstractHandlerMapping类中的getHandler方法。

	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?
        // 如果返回的是handler是String类型的去Spring上线文中根据bean名获取处理器Bean对象
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = obtainApplicationContext().getBean(handlerName);
		}
        //获取处理器执行器链
		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;
	}

在这个方法中存在比较重要的三个方法本文分别针对这些方法做分析

方法1getHandlerInternal(request)

方法2:  getHandlerExecutionChain(handler, request)

方法3getCorsHandlerExecutionChain(request, executionChain, config)

2.1.1 查找内部的处理器

    分析 getHandlerInternal方法发现AbstractHandlerMapping类中的getHandlerInternal方法是一个抽象方法。因为AbstractHandlerMapping和AbstractHandlerMethodMapping是RequestMappingHandlerMapping的父类所以其实现方法在AbstractHandlerMethodMapping中实现的。

	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        //1.获取请求的url
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		if (logger.isDebugEnabled()) {
			logger.debug("Looking up handler method for path " + lookupPath);
		}
		this.mappingRegistry.acquireReadLock();
		try {
            //2.查找url对应的handlerMethod
			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
			if (logger.isDebugEnabled()) {
				if (handlerMethod != null) {
					logger.debug("Returning handler method [" + handlerMethod + "]");
				}
				else {
					logger.debug("Did not find handler method for [" + lookupPath + "]");
				}
			}
            //3.如果handlerMethod不为空则创建一个新的handlerMethod返回
			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
		}
		finally {
			this.mappingRegistry.releaseReadLock();
		}
	}

关注AbstractHandlerMethodMapping类中的lookupHandlerMethod方法

	@Nullable
	protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
		List<Match> matches = new ArrayList<>();
        //根据路径查找在urlLookup属性中查找该属性是一个Map,
        //该属性中的值是在register方法中赋值的register方法的调用可以在我写的上篇文章
        //SpringMvc源码分析二 请求执行前的准备过程
        //@Controller/@RequestMapping注解解析为RequestMappingInfo的过程可以看到
        //返回的类型是List<RequestMappingInfo>类型的数据
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
		if (directPathMatches != null) {
            //如果有匹配的结果生成一个新的RequestMappingInfo对象放入到matches对象中
			addMatchingMappings(directPathMatches, matches, request);
		}
		if (matches.isEmpty()) {
            // 如果通过url没找到则遍历所有的 mappings 匹配匹配类似于 /hello/{name} 的url
            // mappings也是一个mapkey是RequestMappingInfo value是HandlerMethod
			// No choice but to go through all mappings...
			addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
		}
        //找到最佳的匹配并返回对应的handlerMethod

		if (!matches.isEmpty()) {
			Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
			matches.sort(comparator);
			if (logger.isTraceEnabled()) {
				logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
			}
			Match bestMatch = matches.get(0);
			if (matches.size() > 1) {
				if (CorsUtils.isPreFlightRequest(request)) {
					return PREFLIGHT_AMBIGUOUS_MATCH;
				}
				Match secondBestMatch = matches.get(1);
				if (comparator.compare(bestMatch, secondBestMatch) == 0) {
					Method m1 = bestMatch.handlerMethod.getMethod();
					Method m2 = secondBestMatch.handlerMethod.getMethod();
					throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
							request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
				}
			}
			handleMatch(bestMatch.mapping, lookupPath, request);
            //返回handerMethod
			return bestMatch.handlerMethod;
		}
		else {
			return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
		}
	}

最佳匹配的规则如下图的源码所示

优先级分别为

请求方式>路径>参数等等

	protected Comparator<RequestMappingInfo> getMappingComparator(final HttpServletRequest request) {
		return (info1, info2) -> info1.compareTo(info2, request);
	}
public int compareTo(RequestMappingInfo other, HttpServletRequest request) {
		int result;
		// Automatic vs explicit HTTP HEAD mapping
		if (HttpMethod.HEAD.matches(request.getMethod())) {
			result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
			if (result != 0) {
				return result;
			}
		}
		result = this.patternsCondition.compareTo(other.getPatternsCondition(), request);
		if (result != 0) {
			return result;
		}
		result = this.paramsCondition.compareTo(other.getParamsCondition(), request);
		if (result != 0) {
			return result;
		}
		result = this.headersCondition.compareTo(other.getHeadersCondition(), request);
		if (result != 0) {
			return result;
		}
		result = this.consumesCondition.compareTo(other.getConsumesCondition(), request);
		if (result != 0) {
			return result;
		}
		result = this.producesCondition.compareTo(other.getProducesCondition(), request);
		if (result != 0) {
			return result;
		}
		// Implicit (no method) vs explicit HTTP method mappings
		result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
		if (result != 0) {
			return result;
		}
		result = this.customConditionHolder.compareTo(other.customConditionHolder, request);
		if (result != 0) {
			return result;
		}
		return 0;
	}

此时我们就找到了该请求对应的MethodHandler了。

2.1.2 获取处理器执行链 

在AbstractHandlerMapping类 getHandler(HttpServletRequest request)方法中调用的getHandlerExecutionChain(handler, request)方法通过handler和request获取到了该请求的执行器链。分析getHandlerExecutionChain方法。

	protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
        //获取请求路径
		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
			if (interceptor instanceof MappedInterceptor) {
				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                // 判断当前请求路径是否满足interceptor里配置的路径
				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
					chain.addInterceptor(mappedInterceptor.getInterceptor());
				}
			}
			else {
				chain.addInterceptor(interceptor);
			}
		}
		return chain;
	}

1. Interceptors用于配置SpringMVC的拦截器有两种设置方式 通过子类的extendInterceptors钩子方法进行设置 通过子类的extendInterceptors钩子方法进行设置。Interceptors并不会直接使用而是通过initInterceptors方法按类型分配到mappedInterceptors和adaptedInterceptors中进行使用Interceptors只用于配置。
2. mappedInterceptors此类Interceptor在使用时需要与请求的url进行匹配只有匹配成功后才会添加到getHandler的返回值HandlerExecutionChain里。它有两种获取途径从interceptors获取或者注册到spring的容器中通过detectMappedInterceptors方法获取。
3. adaptedInterceptors这种类型的Inerceptor不需要进行匹配在getHandler中会全部添加到返回值HandlerExecutionChain里面。它只能从interceptor中获取。
AbstractHandlerMapping的创建其实就是初始化这三个Interceptor

在AbstractHandlerMapping类中存在initApplicationContext方法。

	protected void initApplicationContext() throws BeansException {
        //扩展拦截器
		extendInterceptors(this.interceptors);
        //在adaptedInterceptors容器中加入MappedInterceptor类型的拦截器
		detectMappedInterceptors(this.adaptedInterceptors);
		initInterceptors();
	}

在上面的源码中

1. extendInterceptors是模板方法用于给子类提供一个添加或者修改Interceptors的入口不过在现有springMVC的实现中并没有使用。
2. detectMappedInterceptors方法用于将SpringMVC容器及父容器中的所有MappedInterceptor类型的Bean添加到mappedInterceptors属性。
3. initInterceptors方法的作用是初始化Interceptor具体内容其实是interceptors属性里所包含的对象按类型添加到mappedInterceptors或者adaptedInterceptors

DelegatingWebMvcConfiguration类中的方法可以通过实现WebMvcConfigurer中的addInterceptors方法并往其中添加实现HandlerInterceptor接口的拦截器然后将实现WebMvcConfigurer接口的类纳入Spring容器管理来实现自定义拦截器

源码一往WebMvcConfigurerComposite里的delegate添加自定义拦截器

	@Autowired(required = false)
	public void setConfigurers(List<WebMvcConfigurer> configurers) {
		if (!CollectionUtils.isEmpty(configurers)) {
			this.configurers.addWebMvcConfigurers(configurers);
		}
	}

 源码二往registry添加从delegate取到的自定义拦截器

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		for (WebMvcConfigurer delegate : this.delegates) {
			delegate.addInterceptors(registry);
		}
	}

2.1.3获取跨域处理执行链

 AbstractHandlerMapping类中的getCorsHandlerExecutionChain方法的作用是通过读取跨域配置往拦截器链中添加拦截器

protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
			HandlerExecutionChain chain, @Nullable CorsConfiguration config) {

		if (CorsUtils.isPreFlightRequest(request)) {
			HandlerInterceptor[] interceptors = chain.getInterceptors();
			chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
		}
		else {
            //添加跨域拦截器
			chain.addInterceptor(new CorsInterceptor(config));
		}
		return chain;
	}

2.2封装处理器链适配器

方法二getHandlerAdapter(mappedHandler.getHandler())  获取处理器适配器。

	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
            //循环所有的适配器获取符合要求的适配器
			for (HandlerAdapter ha : this.handlerAdapters) {
				if (logger.isTraceEnabled()) {
					logger.trace("Testing handler adapter [" + ha + "]");
				}
                //判断适配器是否支持该方法处理器此处符合要求的适配器是
                //RequestMappingHandlerAdapter
				if (ha.supports(handler)) {
					return ha;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Spring

“SpringMvc源码分析(三) 请求执行过程之获取MethodHandler” 的相关文章