请求处理过程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<>();
		//获取到直接路径 (请求路径)
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
		//如果不是restful风格 也就是参数不通过路径传的话
		if (directPathMatches != null) {
		    //找到完全匹配的则将mappings、handlerMethod 添加到上面定义的matches集合中
		    //directPathMatches中是请求路径 封装成了RequestMappingInfo类型
		    //matches是空集合 上面定义的 类型是Match
		    //Match有两个属性 mapping:RequestMappingInfo类型的, registration:保存了处理方法和方法所在的类
		    //controller中每个方法上面配置的路径都会被解析出来,放
		    //到AbstractHandlerMethodMapping.MappingRegistry的registry属性中 是1个map
		    //key是请求路径 value是registration类型 保存方法名和类名 addMatchingMappings时根据传入的directPathMatches获取
		    //关键方法 通过请求路径 获取对应的controller
			addMatchingMappings(directPathMatches, matches, request);
		}
		//如果是restful风格 也就是参数通过路径传的话
		if (matches.isEmpty()) {
			// No choice but to go through all mappings...
			//这里第一个参数传入了所有的请求路径 遍历进行匹配
			//AbstractHandlerMethodMapping.MappingRegistry的registry属性的key
			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);
			//返回这个最佳method
			return bestMatch.handlerMethod;
		}
		else {
			return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
		}
	}

AbstractHandlerMethodMapping#addMatchingMappings

	private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
		//遍历传进来的mappings 一般是一个RequestMappingInfo类型的集合
		for (T mapping : mappings) {
			//这里也是获取到RequestMappingInfo
			T match = getMatchingMapping(mapping, request);
			if (match != null) {
				//构建1个新的Match对象 有请求路径 和处理方法及方法所在的类
				matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
			}
		}
	}

至此就把这个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方法中实现,还需要细细研究啊~~~

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值