spring boot DispatcherServlet(二)handler查找

本文深入探讨了Spring Boot的DispatcherServlet如何处理请求,从service到doDispatch,特别是getHandler方法,详细分析了匹配handler的过程,包括对多个handler的排序和选择最佳匹配,并解释了HandlerExecutionChain的生成以及HandlerAdapter的选择原则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DispatcherServlet的请求处理

既然要分析请求处理过程,肯定需要看service方法,但是DispatcherServlet并没有直接实现service方法,而是由父类FrameworkServlet实现的service方法

service
protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
	// 获取当前请求的请求方法,get post 等
	HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
	// 如果是patch 或者没有解析出方法,那么会调用processRequest
	if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
		processRequest(request, response);
	}
	else {
		// 其他情况,比如请求方法是get post等,会调用父类的service
		super.service(request, response);
	}
}

接着看父类HttpServlet的service方法

protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {

    String method = req.getMethod();
	// 根据请求方法类型的不同,执行相应的do方法
    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;
            try {
                ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
            } catch (IllegalArgumentException iae) {
                // Invalid date header - proceed as if none was set
                ifModifiedSince = -1;
            }
            if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                // 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);
    }
}
doGet

这里可以看下DispatcherServlet的doGet doPost

protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

	processRequest(request, response);
}
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

	processRequest(request, response);
}
processRequest

可以看到,最终都会调用processRequest方法吗,主要调用doService来处理请求

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

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

	// 省略
}
doService

下面看下doService方法,doService主要对请求进行一些加工,然后将请求交给doDispatch来进行处理

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
	logRequest(request);

	// 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.
	// 将webapplication添加到请求中
	request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
	// 将localResolver添加到请求中
	request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
	// 将themeResolver添加到请求中
	request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
	// 将themeSource添加到请求中
	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

接下来看下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 {
		ModelAndView mv = null;
		Exception dispatchException = null;

		try {
			// 这里会根据请求的contentType是否是以multipart/开头,来判断是否是multipart类型的请求,如果是会使用原始的请求对象来创建一个MultipartHttpServletRequest类型的请求
			processedRequest = checkMultipart(request);
			// 判断是否进行了multipart类型的转换
			multipartRequestParsed = (processedRequest != request);

			// Determine handler for the current request.
			// 判断使用哪个handler
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {
				// 返回404
				noHandlerFound(processedRequest, response);
				return;
			}

			// Determine handler adapter for the current request.
			// 遍历所有的handlerAdapter,调用support,判断是否支持当前映射,然后返回支持当前handler的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;
				}
			}
			
			// 执行interceptor的prehandle
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

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

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

			applyDefaultViewName(processedRequest, mv);
			// 执行interceptor的postHandle
			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);
			}
		}
	}
}
getHandler
匹配handler

下面详细分析下dispatcherServlet是如何根据请求来找到对应的controller的方法的

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	// 遍历5个handlerMapping,找到能够处理当前请求的handlerMapping,然后进行处理
	// 这里主要关注RequestMappingHandlerMapping是如何处理的
	if (this.handlerMappings != null) {
		for (HandlerMapping mapping : this.handlerMappings) {
			HandlerExecutionChain handler = mapping.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
	}
	return null;
}

下面首先看下父类AbstractHandlerMapping的getHandler

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	// 获取handler,由子类实现
	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 = obtainApplicationContext().getBean(handlerName);
	}

	// 获取执行链
	HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

	if (logger.isTraceEnabled()) {
		logger.trace("Mapped to " + handler);
	}
	else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
		logger.debug("Mapped to " + executionChain.getHandler());
	}

	// 跨域相关
	// 这里会判断是否配置了跨域,如果配置了跨域,会将跨域的处理加入到执行链中
	if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
		CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
		CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
		config = (config != null ? config.combine(handlerConfig) : handlerConfig);
		executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
	}

	return executionChain;
}

这里看下RequestMappingInfoHandlerMapping的getHandlerInternal

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
	request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
	try {
		// 这里调用父类的getHandlerInternal
		return super.getHandlerInternal(request);
	}
	finally {
		ProducesRequestCondition.clearMediaTypesAttribute(request);
	}
}

接着看下AbstractHandlerMethodMapping的getHandlerInternal

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
	request.setAttribute(LOOKUP_PATH, lookupPath);
	this.mappingRegistry.acquireReadLock();
	try {
		// 使用路径来查找handler
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	finally {
		this.mappingRegistry.releaseReadLock();
	}
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
	List<Match> matches = new ArrayList<>();
	// 1. 从urlLookup这个map中查找,之前分析过,这个urlLookup中存放的是直接url
	List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
	if (directPathMatches != null) {
		addMatchingMappings(directPathMatches, matches, request);
	}
	// 2. 如果从urlLookup中没有找到匹配的,那么从所有的映射关系中查找匹配的
	if (matches.isEmpty()) {
		// No choice but to go through all mappings...
		addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
	}

	if (!matches.isEmpty()) {
		// 3. 有多个匹配的,对它们排序,选出最佳匹配的
		Match bestMatch = matches.get(0);
		if (matches.size() > 1) {
			Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
			matches.sort(comparator);
			bestMatch = matches.get(0);
			if (logger.isTraceEnabled()) {
				logger.trace(matches.size() + " matching mappings: " + matches);
			}
			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();
				String uri = request.getRequestURI();
				throw new IllegalStateException(
						"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
			}
		}
		request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
		handleMatch(bestMatch.mapping, lookupPath, request);
		return bestMatch.handlerMethod;
	}
	else {
		return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
	}
}

上述方法的主要目的就是找到能够匹配当前请求的handler,如果找到多个,那么返回最佳匹配的handler
下面看下addMatchingMappings,看看它是如何判断一个映射是否匹配当前请求的

private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
	// mappings是给定的映射范围,从这些映射中查找匹配当前请求的映射
	// 分别从请求方法、参数、请求头、请求内容类型、响应内容类型、请求路径、自定义条件几个方面来判断映射是否匹配当前的请求
	for (T mapping : mappings) {
		T match = getMatchingMapping(mapping, request);
		if (match != null) {
			matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
		}
	}
}
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
	return info.getMatchingCondition(request);
}
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
	// methods匹配,判断当前请求方法(get,post等),是否匹配RequestMapping的method属性
	RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
	if (methods == null) {
		return null;
	}
	// 请求参数匹配,对应RequestMapping注解的params属性
	ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
	if (params == null) {
		return null;
	}
	// 请求头匹配,对应RequestMapping的heades属性
	HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
	if (headers == null) {
		return null;
	}
	// 请求内容类型匹配,对应RequestMapping的consumes
	ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
	if (consumes == null) {
		return null;
	}
	// 响应内容类型匹配,对应RequestMapping的produces
	ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
	if (produces == null) {
		return null;
	}
	// 请求路径匹配,对应RequestMapping的patterns 
	PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
	if (patterns == null) {
		return null;
	}
	// 用户自定义的条件
	RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
	if (custom == null) {
		return null;
	}

	return new RequestMappingInfo(this.name, patterns,
			methods, params, headers, consumes, produces, custom.getCondition());
}

接着看下有多个映射都匹配当前请求时,如何通过排序来获取最佳匹配映射

对多个handler进行排序
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
protected Comparator<RequestMappingInfo> getMappingComparator(final HttpServletRequest request) {
	return (info1, info2) -> info1.compareTo(info2, request);
}

可以看到排序规则,就是简单地调用RequestMappingInfo的compareTo,然后根据@RequestMapping注解的每个属性分别进行比较

public int compareTo(RequestMappingInfo other, HttpServletRequest request) {
		int result;
		// Automatic vs explicit HTTP HEAD mapping
		// 1. 当前的请求是head
		// 使用methodsCondition来进行比较
		// 0 两个映射具有相同数量的请求method
		// -1 当前映射具有比其他映射更多的请求method
		// 1 当前映射具有比其他映射更少的请求method
		if (HttpMethod.HEAD.matches(request.getMethod())) {
			result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
			if (result != 0) {
				return result;
			}
		}
		// 2. 通过pattern进行比较
		result = this.patternsCondition.compareTo(other.getPatternsCondition(), request);
		if (result != 0) {
			return result;
		}
		// 3. 通过params进行比较
		result = this.paramsCondition.compareTo(other.getParamsCondition(), request);
		if (result != 0) {
			return result;
		}
		// 4. 通过headers进行比较
		result = this.headersCondition.compareTo(other.getHeadersCondition(), request);
		if (result != 0) {
			return result;
		}
		// 5. 通过consumes进行比较
		result = this.consumesCondition.compareTo(other.getConsumesCondition(), request);
		if (result != 0) {
			return result;
		}
		// 6. 通过produces进行比较
		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;
	}
生成HandlerExecutionChain

接下来看下如何获取HandlerExecutionChain

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
	HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
			(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

	String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
	// 遍历所有的interceptor
	for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
		// 如果当前interceptor的类型是MappedInterceptor,那么会判断该interceptor是否匹配当前的请求
		// 如果匹配当前的请求,那么将这个interceptor加入到executionChain中
		if (interceptor instanceof MappedInterceptor) {
			MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
			if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
				chain.addInterceptor(mappedInterceptor.getInterceptor());
			}
		}
		else {
			chain.addInterceptor(interceptor);
		}
	}
	return chain;
}
getHandlerAdapter

默认情况下会有如下4个adapter
在这里插入图片描述

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	if (this.handlerAdapters != null) {
		for (HandlerAdapter adapter : this.handlerAdapters) {
			if (adapter.supports(handler)) {
				return adapter;
			}
		}
	}
	throw new ServletException("No adapter for handler [" + handler +
			"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

在调用supports来判断handlerAdapter是否支持当前请求时,主要是判断handler是否是指定的类型
比如RequestMappingHandlerAdapter就是判断handler是否是HandlerMethod类型的

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值