返回

Spring5 MVC——从映射关系里获取处理请求的逻辑实例

发布时间:2023-01-10 22:27:25 234
# java# java# ios# 容器# 信息

SpringMVC的核心流程

  • 建立请求和Controller方法的映射集合的流程。

  • 根据请求查找对应的Controller方法的流程。

  • 请求参数绑定到方法形参,执行方法处理请求,返回结果进行视图渲染的流程。

RequestMappingHandlerMapping继承类图

HandlerMapping

HandlerMapping接口作用是将请求映射到处理程序,以及预处理和处理后的拦截器列表,映射是基于一些标准的,其中的细节因不同的实现而不相同。这是官方文档上一段描述,该接口只有一个方法getHandler(request),返回一个HandlerExecutionChain对象,接口本身很简单。

public interface HandlerMapping {


    String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler";


    String LOOKUP_PATH = HandlerMapping.class.getName() + ".lookupPath";


    String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";


    String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";


    String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";


    String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";


    String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";


    String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";

    // 返回请求的一个处理程序handler和拦截器interceptors
    @Nullable
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

}

HandlerExecutionChain

HandlerExecutionChain 是Handler执行链,包含handler Object、interceptor。所以HandlerExecutionChain 提供了getHandler、getInterceptors方法,配置文件中配置的interceptor都会加入到HandlerExecutionChain。

public class HandlerExecutionChain {

	//handler实例
	private final Object handler;

	//一组拦截器实例
	@Nullable
	private HandlerInterceptor[] interceptors;

	//HandlerInterceptor的链表
	@Nullable
	private List interceptorList;

	......
}

AbstractHandlerMapping

从类图中可知,HandlerMapping主要由AbstractHandlerMapping实现。

public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
        implements HandlerMapping, Ordered, BeanNameAware {

	@Override
	@Nullable
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		//获取handler的具体逻辑,留给子类实现
		Object handler = getHandlerInternal(request);
		// 如果获取到的handler为null,则采用默认的handler,即属性defaultHandler
		if (handler == null) {
			handler = getDefaultHandler();
		}
		if (handler == null) {
			//如果连DefaultHandler也为空,则直接返回空
			return null;
		}
		// Bean name or resolved handler?
		//如果handler是beanName,从容器里获取对应的bean
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = obtainApplicationContext().getBean(handlerName);
		}

		//根据handler和request获取处理器链HandlerExecutionChain
		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;
	}
}

  • 用户发起请求,会进入到AbstractHandlerMapping类中的getHandler方法中。

  • 沿着方法的调用栈发现,请求先经过FrameworkServlet的service方法去处理。

  • 在由HttpServlet的service方法转发到FrameworkServlet的doPost方法中。

  • doPost方法中会调用FrameworkServlet的processRequest方法。

  • processRequest方法会调用DispatcherServlet的doService方法。

  • doService方法会调用DispatcherServlet的doDispatch方法。

  • doDispatch方法会调用到DispatcherServlet的getHandler方法。

  • DispatcherServlet的getHandler方法会调用到AbstractHandlerMapping中的getHandler方法。

DispatcherServlet#doDispatch

public class DispatcherServlet extends FrameworkServlet {

	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);

				// Determine handler for the current request.
				// 根据当前request获取HandlerExecutionChain,
				// HandlerExecutionChain中包含了请求url,以及对应的controller以及controller中的方法
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				// 通过HandlerExecutionChain获取对应的适配器,adapter负责完成参数解析
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				//处理GET、HEAD请求的Last-modified
				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.
				// 调用目标Controller中的方法
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				// 处理成默认视图名,也就是添加前缀和后缀等
				applyDefaultViewName(processedRequest, mv);
				// 拦截器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);
				}
			}
		}
	}
}

DispatcherServlet#getHandler

  • 根据request信息uri找到对应HandlerExecutionChain执行链,HandlerExecutionChain中包含了请求url,以及对应的controller以及controller中的方法。
public class DispatcherServlet extends FrameworkServlet {

	@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}
}
  • 该方法会依次调用DispatcherServlet类中的成员变量List handlerMappings中的HandlerMapping的实现类的getHandler方法。

handlerMappings中包含4个HandlerMapping的实现类

  • requestMappingHandlerMapping -> RequestMappingHandlerMapping
  • beanNameHandlerMapping -> BeanNameUrlHandlerMapping
  • routerFunctionMapping -> RouterFunctionMapping
  • defaultServletHandlerMapping -> SimpleUrlHandlerMapping

这里主要关注RequestMappingHandlerMapping

  • 因为其他的HandlerMapping实现类并不会对主流的RequestMapping注解进行处理。
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
		implements HandlerMapping, Ordered, BeanNameAware {

	@Override
	@Nullable
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		//获取handler的具体逻辑,留给子类实现
		Object handler = getHandlerInternal(request);
		// 如果获取到的handler为null,则采用默认的handler,即属性defaultHandler
		if (handler == null) {
			handler = getDefaultHandler();
		}
		if (handler == null) {
			//如果连DefaultHandler也为空,则直接返回空
			return null;
		}
		// Bean name or resolved handler?
		//如果handler是beanName,从容器里获取对应的bean
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = obtainApplicationContext().getBean(handlerName);
		}

		//根据handler和request获取处理器链HandlerExecutionChain
		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;
	}
}

getHandlerInternal

  • 从AbstractHandlerMapping的子类方法实现里获取到真正的Handler实例。
public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping {

	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
		try {
			return super.getHandlerInternal(request);
		}
		finally {
			ProducesRequestCondition.clearMediaTypesAttribute(request);
		}
	}
}


public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMapping implements InitializingBean {

	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		// 获取 request 中的 url,用来匹配 handler
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		request.setAttribute(LOOKUP_PATH, lookupPath);
		this.mappingRegistry.acquireReadLock();
		try {
			// 根据路径寻找 Handler,并封装成 HandlerMethod
			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
			// 根据 handlerMethod 中的 bean 来实例化 Handler,并添加进 HandlerMethod
			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
		}
		finally {
			this.mappingRegistry.releaseReadLock();
		}
	}
}

AbstractHandlerMethodMapping#lookupHandlerMethod

  • 根据路径寻找Handler,并封装成 HandlerMethod
public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMapping implements InitializingBean {

	@Nullable
	protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
		List matches = new ArrayList<>();
		// 通过 lookupPath 属性中查找。如果找到了,就返回对应的RequestMappingInfo
		List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
		if (directPathMatches != null) {
			// 如果匹配到了,检查其他属性是否符合要求,如请求方法,参数,header 等
			addMatchingMappings(directPathMatches, matches, request);
		}
		if (matches.isEmpty()) {
			// No choice but to go through all mappings...
			// 没有直接匹配到,则遍历所有的处理方法进行通配符匹配
			addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
		}

		if (!matches.isEmpty()) {
			Match bestMatch = matches.get(0);
			// 如果有多个匹配的,会找到第二个最合适的进行比较
			if (matches.size() > 1) {
				// 如果方法有多个匹配,不同的通配符等,则排序选择出最合适的一个
				Comparator 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);
			// 设置 request 参数(RequestMappingHandlerMapping 对其进行了覆写)
			handleMatch(bestMatch.mapping, lookupPath, request);
			// 返回匹配的 url 的处理的方法
			return bestMatch.handlerMethod;
		}
		else {
			// 调用 RequestMappingHandlerMapping 类的 handleNoMatch 方法再匹配一次
			return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
		}
	}
}

AbstractHandlerMapping#getHandlerExecutionChain

  • 根据handler和request获取处理器链HandlerExecutionChain
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
		implements HandlerMapping, Ordered, BeanNameAware {

	protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		//判断handler是不是执行器链,如果不是则创建一个执行器链
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
		//包装拦截器
		/**
		 * 		
		 * 			
		 * 			
		 * 		
		 */
		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;
	}
}

到此,根据请求查找对应的Controller方法的流程就梳理完毕了。

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线