请求处理过程1-获取HandlerMapping

1.确定由哪个controller处理这次请求

HandlerMapping(处理器映射器)可以将请求映射到对应的Handler(controller)上
一个请求进来,想要处理这个请求,首先得确定由哪个方法处理,这个功能由requestMappingHandlerMapping以及他的父类们共同完成,调用这些类的成员方法完成。
在这里插入图片描述

请求进来会到DispatcherServlet类的doDispatch方法
在这里插入图片描述
通过 getHandler方法 就获得了当前请求的处理对象,也就是controller。

1.getHandler方法

	@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    
    
		//遍历handlerMappings  一共有5个 这里用到requestMappingHandlerMapping 在mvcAutoConfigue会自动导入 handlerMappings会在第一次请求时调用initHandlerMappings完成导入
		if (this.handlerMappings != null) {
    
    
			for (HandlerMapping mapping : this.handlerMappings) {
    
    
				//找到实际的处理方法 也就是controller  这里注意类型是HandlerExecutionChain
				//这里边有handler和 HandlerInterceptor 
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
    
    
					return handler;
				}
			}
		}
		return null;
	}

WebMvcAutoConfiguration.java中自动导入requestMappingHandlerMapping
在这里插入图片描述

第一次访问时,初始化handlerMappings ,一共5个
在这里插入图片描述

2.继续调用requestMappingHandlerMapping的getHandler方法

这个是在AbstractHandlerMapping类中

	@Override
	@Nullable
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    
    
	    //获取handler 也就是controller
		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 类型
		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)) {
    
    
			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;
	}

3.getHandlerInternal方法

RequestMappingHandlerMapping类中

	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    
    
		try {
    
    
			//调用父类的getHandlerInternal方法
			return super.getHandlerInternal(request);
		}
		finally {
    
    
			ProducesRequestCondition.clearMediaTypesAttribute(request);
		}
	}

4.继续getHandlerInternal方法

1.从request中获取到对应的请求路径 UrlPathHelper是一个工具类获取请求路径
2.根据请求路径获取到合适的HandlerMethod对象并返回

	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    
    
	    //获取到请求的路径 (找到controller就通过这个路径)
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		//将解析出来的请求路径放入request 方便后续直接从request中获取使用
		request.setAttribute(LOOKUP_PATH, lookupPath);
		//加锁
		this.mappingRegistry.acquireReadLock();
		try {
    
    
			//主要方法 找到controller
			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
			//对HandlerMethod进行实例赋值(因为HanlerMethod中的bean属性是该方法对应对应的类对象
            //这里通过createWithResolvedBean会将spring容器中的HandlerMethod所属的bean实例赋值)
			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
		}
		finally {
    
    
			//释放锁
			this.mappingRegistry.releaseReadLock();
		}
	}

5.lookupHandlerMethod方法

根据请求request和对应的请求路径lookupPath获取对应的HandlerMethod
在AbstractHandlerMethodMapping类中

	@Nullable
	protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    
    
	    //创建集合 用来存储请求路径和处理方法(controller)
		List<Match> matches = new ArrayList<>();
		//获取到直接路径 也就是controller上配置的路径
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
		if (directPathMatches != null) {
    
    
		    //找到完全匹配的则将mappings、handlerMethod 添加到matches中
			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()) {
    
    
			Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
			matches.sort(comparator);
			//获取到最佳的Match 也就是最佳的controller
			Match bestMatch = matches.get(0);
			if (matches.size() > 1) {
    
    
				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 + "}");
				}
			}
			//将匹配的HandlerMethod 存放到request中 方便后期使用
			request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
			//获取的请求mapping进行处理(主要是针对pattern类型进行 请求路径url和请求参数的解析存放request)Pattern模式:localhost:port/context/book/book/{id}有不确定的参数
			handleMatch(bestMatch.mapping, lookupPath, request);
			//返回这个最佳controller
			return bestMatch.handlerMethod;
		}
		else {
    
    
			return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
		}
	}

至此就把这个congtroller选出来了。

总结:
1.请求进来先调用doDispatch方法。
2.调用DispatcherServlet类的getHandler方法。遍历handlerMappings ,调用getHandler方法,如果可以获取到handler,就返回,跳出遍历。这里在第一个循环就会找到handler(controller),标注了@xxxMapping注解的controler都会通过requestMappingHandlerMapping实现。
3.继续调用requestMappingHandlerMapping的getHandler方法,执行getHandlerInternal方法(最终会调用AbstractHandlerMethodMapping类的getHandlerInternal方法),然后将获取到的handler封装成HandlerExecutionChain类型返回,这个类中有handler和 HandlerInterceptor。
4.AbstractHandlerMethodMapping类的getHandlerInternal方法会调用lookupHandlerMethod方法,然后将获取到的handler也就是controller返回。
5.lookupHandlerMethod会根据请求路径,找到最佳的handler(controller)返回。
6.最终返回到doDispatch类中,DispatcherServlet类的getHandler方法完成。获取到HandlerExecutionChain类型的mappedHandler。

大致流程是这样,其中有太多细节,具体是怎么通过路径获取到的controller的呢,肯定是在最后的lookupHandlerMethod方法中实现,还需要细细研究啊~~~

猜你喜欢

转载自blog.csdn.net/weixin_46666822/article/details/124749832