• 【SpringMVC】处理器的封装和请求寻找到对应处理器的过程


    本文依旧是对该文件的补充说明:

    详解SpringMVC请求的时候是如何找到正确的Controller

    处理的封装

    自己编写的Controller是如何变成springmvc中的处理器的呢?
    在初始化组件的时候。initHandlerMappings(context);是初始化组件名为处理器映射器。顾名思义,就是将处理器和处理器的一些信息映射起来。当请求来的时候,比较信息找到对应的处理器。

    	protected void initStrategies(ApplicationContext context) {
    		initMultipartResolver(context);
    		initLocaleResolver(context);
    		initThemeResolver(context);
    		initHandlerMappings(context);
    		initHandlerAdapters(context);
    		initHandlerExceptionResolvers(context);
    		initRequestToViewNameTranslator(context);
    		initViewResolvers(context);
    		initFlashMapManager(context);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    实际上在使用时,解析该标签的时候,springmvc就已经将组件实例化到容器中了。org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
    这个类实现了InitializingBean 接口,所以关注下afterPropertiesSet() 方法,看下实例化完成后,做什么什么工作。

    直接进入到方法
    org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initHandlerMethods

    	protected void initHandlerMethods() {
    		// 得到所有的Object的bean名称
    		for (String beanName : getCandidateBeanNames()) {
    			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
    				processCandidateBean(beanName);
    			}
    		}
    		handlerMethodsInitialized(getHandlerMethods());
    	}
    
    	protected void processCandidateBean(String beanName) {
    		Class<?> beanType = null;
    		try {
    			beanType = obtainApplicationContext().getType(beanName);
    		}
    		catch (Throwable ex) {
    			// An unresolvable bean type, probably from a lazy bean - let's ignore it.
    			if (logger.isTraceEnabled()) {
    				logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
    			}
    		}
    		// RequestMappingHandlerMapping重写了该方法,类有@Controller注解或者有@RequestMapping注解
    		if (beanType != null && isHandler(beanType)) {
    			// 如果该类符合,就从该类找找处理器方法。
    			detectHandlerMethods(beanName);
    		}
    	}
    
    	protected void detectHandlerMethods(Object handler) {
    		Class<?> handlerType = (handler instanceof String ?
    				obtainApplicationContext().getType((String) handler) : handler.getClass());
    
    		if (handlerType != null) {
    			Class<?> userType = ClassUtils.getUserClass(handlerType);
    			// 遍历这个类的所有方法,根据条件,筛选出所有符合的方法。
    			// 这个方法用@RequestMapping注解注释,并从中解析出RequestMappingInfo
    			// T 就是RequestMappingInfo
    			Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
    					(MethodIntrospector.MetadataLookup<T>) method -> {
    						try {
    							return getMappingForMethod(method, userType);
    						}
    						catch (Throwable ex) {
    							throw new IllegalStateException("Invalid mapping on handler class [" +
    									userType.getName() + "]: " + method, ex);
    						}
    					});
    			if (logger.isTraceEnabled()) {
    				logger.trace(formatMappings(userType, methods));
    			}
    			// key是method
    			// value是RequestMappingInfo
    			methods.forEach((method, mapping) -> {
    				Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
    				// 注册处理器方法的映射关系。
    				registerHandlerMethod(handler, invocableMethod, mapping);
    			});
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    有两个步骤;1;从方法中解析出RequestMappingInfo,2;注册对应关系。

    从方法中解析出RequestMappingInfo

    getMappingForMethod(method, userType);

    	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    		// 从方法中解析出RequestMappingInfo 
    		RequestMappingInfo info = createRequestMappingInfo(method);
    		if (info != null) {
    			// 从类中解析出RequestMappingInfo 
    			RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
    			if (typeInfo != null) {
    				// 如果类中有,则进行合并
    				info = typeInfo.combine(info);
    			}
    			String prefix = getPathPrefix(handlerType);
    			if (prefix != null) {
    				info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
    			}
    		}
    		return info;
    	}
    
    	protected RequestMappingInfo createRequestMappingInfo(
    			RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
    		
    		// 通过注解中的信息,创建RequestMappingInfo信息
    		RequestMappingInfo.Builder builder = RequestMappingInfo
    				.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
    				.methods(requestMapping.method())
    				.params(requestMapping.params())
    				.headers(requestMapping.headers())
    				.consumes(requestMapping.consumes())
    				.produces(requestMapping.produces())
    				.mappingName(requestMapping.name());
    		if (customCondition != null) {
    			builder.customCondition(customCondition);
    		}
    		return builder.options(this.config).build();
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    注册处理器的对应关系

    		public void register(T mapping, Object handler, Method method) {
    			// Assert that the handler method is not a suspending one.
    			if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
    				throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
    			}
    			this.readWriteLock.writeLock().lock();
    			try {
    				//创建新的类HandlerMethod 
    				HandlerMethod handlerMethod = createHandlerMethod(handler, method);
    				validateMethodMapping(handlerMethod, mapping);
    				// 放到map中,
    				this.mappingLookup.put(mapping, handlerMethod);
    			
    				// 得到直接url,什么是直接url呢?
    				// 就是不含*,?,{}的,
    				List<String> directUrls = getDirectUrls(mapping);
    				// 同样是放入map中
    				// key是url,value是RequestMappingInfo
    				for (String url : directUrls) {
    					this.urlLookup.add(url, mapping);
    				}
    
    				String name = null;
    				if (getNamingStrategy() != null) {
    					name = getNamingStrategy().getName(handlerMethod, mapping);
    					// 这里还有一个map,放处理器的名称和处理器的对应关系
    					addMappingName(name, handlerMethod);
    				}
    
    				CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
    				if (corsConfig != null) {
    					this.corsLookup.put(handlerMethod, corsConfig);
    				}
    
    				this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
    			}
    			finally {
    				this.readWriteLock.writeLock().unlock();
    			}
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    ok 到此,处理器的处理已经完成,小结下;遍历所有的bean从中找@controller或者@Requestmapping注解的类。找到后,遍历这个类的所有方法,从中解析出@requestMapping注解中的信息。最后注册处理器的对应关系。两个map;一个放requestmapping和处理器的对应关系,一个放直接url和requestMapping的对应关系。

    如何找到请求对应的处理器

    在处理请求前,springmvc已经将封装了所有的处理器。根据什么规则找到对应的处理器呢?

    	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;
    	}
    	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    		// 得到路径,这个应该是请求路径,就是url中,除了项目路径的,
    		// /springmvcdemo/hello   这里的lookupPath就是/hello
    		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    		request.setAttribute(LOOKUP_PATH, lookupPath);
    		this.mappingRegistry.acquireReadLock();
    		try {
    			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<>();
    		// 根据直接的url中的到Requestmapping
    		// 如果能得到,检查Requestmapping是否匹配,匹配就添加到matches中
    		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    		if (directPathMatches != null) {
    			addMatchingMappings(directPathMatches, matches, request);
    		}
    		// 如果不匹配,则遍历整个requestmapping和处理器的map,找匹配的。
    		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 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 + "}");
    				}
    			}
    			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);
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    关注下排序是根据什么规则排序的。

    	protected Comparator<RequestMappingInfo> getMappingComparator(final HttpServletRequest request) {
    		return (info1, info2) -> info1.compareTo(info2, request);
    	}
    
    • 1
    • 2
    • 3
    	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;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    每个条件都有不同的比较规则。

  • 相关阅读:
    应用层协议不难理解,其实它们就出现在你熟悉的地方
    Aws Ec2服务器设置密码登录
    Go: 关于定时任务
    kubernetes测试部署一个nginx
    js xlsx自定义样式导出
    计算GAN生成图像数据集的平均SSIM
    python笔记
    关于 Cesium 的笔记 (小白学习哈)
    第三章、数据链路层
    elasticsearch创建索引和mapping
  • 原文地址:https://blog.csdn.net/qq_34501351/article/details/126123373