源码解析SpringMVC之RequestMapping注解原理

1、启动初始化

核心:得到应用上下文中存在的全部bean后依次遍历,分析每一个目标handler & 目标方法存在的注解@RequestMapping,将其相关属性封装为实例RequestMappingInfo。最终将 uri & handler 之间的映射关系维护在类AbstractHandlerMethodMapping中的内部类RequestMappingInfo中。

利用RequestMappingHandlerMappingInitializingBean接口特性来完成请求 uri & handler 之间的映射关系。具体详情参考其父类AbstractHandlerMethodMapping实现其功能,如下:

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
	//内部类
	private final MappingRegistry mappingRegistry = new MappingRegistry();
	
	protected void initHandlerMethods() {
		for (String beanName : getCandidateBeanNames()) {//从应用上下文中获取全部的bean
			processCandidateBean(beanName);
		}
	}
	
	protected void processCandidateBean(String beanName) {
		Class<?> beanType = obtainApplicationContext().getType(beanName);
		// 判断是否为Handler的条件为:是否存在注解Controller 或者 RequestMapping
		if (beanType != null && isHandler(beanType)) {
			detectHandlerMethods(beanName);
		}
	}
		
	protected void detectHandlerMethods(Object handler) {//handler为String类型的beanName
		Class<?> handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());
		if (handlerType != null) {
			Class<?> userType = ClassUtils.getUserClass(handlerType);
			// 集合methods其key:反射中Method类。value:RequestMappingInfo
			Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
					(MethodIntrospector.MetadataLookup<T>) method -> {
						// 调用具体的实现类,例如RequestMappingHandlerMapping
						return getMappingForMethod(method, userType);
					});
			methods.forEach((method, mapping) -> {
				Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
				registerHandlerMethod(handler, invocableMethod, mapping);
			});
		}
	}
	
	protected void registerHandlerMethod(Object handler, Method method, T mapping) {
		this.mappingRegistry.register(mapping, handler, method);
	}
}

1.1、RequestMappingHandlerMapping

解析目标类 & 目标方法之@RequestMapping注解相关属性。

public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping{
	@Override
	@Nullable
	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
		//将目标方法存在的@RequestMapping注解相关属性封装为RequestMappingInfo
		RequestMappingInfo info = createRequestMappingInfo(method);
		if (info != null) {
			//如果目标handler也存在@RequestMapping注解,则也封装为RequestMappingInfo
			RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
			if (typeInfo != null) {
				// 将目标方法@RequestMapping相关属性与目标handler之@RequestMapping相关属性合并起来
				info = typeInfo.combine(info);
			}
			String prefix = getPathPrefix(handlerType);//获取目标handler之url前缀
			if (prefix != null) {
				info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
			}
		}
		return info;
	}
	
	private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
		RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
		return (requestMapping != null ? createRequestMappingInfo(requestMapping, null) : null);
	}
	
	protected RequestMappingInfo createRequestMappingInfo(RequestMapping requestMapping,RequestCondition condition) {
		// 获取某个具体目标方法其@RequestMapping注解相关属性,最终封装为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());
		return builder.options(this.config).build();
	}
}

1.2.MappingRegistry

public abstract class AbstractHandlerMethodMapping<T> {

	class MappingRegistry {
		private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
		//集合mappingLookup之key:RequestMappingInfo。value:HandlerMethod
		private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
		private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
		
		public void register(T mapping, Object handler, Method method) {
			...
			// 目标类的目标方法最终封装为HandlerMethod  handler实为目标bean的beanName
			HandlerMethod handlerMethod = createHandlerMethod(handler, method);
			this.mappingLookup.put(mapping, handlerMethod);
			List<String> directUrls = getDirectUrls(mapping);
			for (String url : directUrls) {
				this.urlLookup.add(url, mapping);
			}
			...
			this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
		}
	}
}

2、处理请求

SpringMVC利用请求url获取目标handler。
源码解析SpringMVC之RequestMapping注解原理_第1张图片

public class DispatcherServlet extends FrameworkServlet {
	@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				// 围绕 RequestMappingHandlerMapping 展开
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}
}
public abstract class AbstractHandlerMethodMapping<T>  implements InitializingBean {
	private final MappingRegistry mappingRegistry = new MappingRegistry();
	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request){
		// 获取requestUri
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		// 从 mappingRegistry 获取目标handler
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	
	protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) {
		List<Match> matches = new ArrayList<>();
		// 利用 lookupPath 从MappingRegistry相关属性中获取目标handler之T
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
		// 通过章节1得知,返回的类为 RequestMappingInfo,即@RequestMapping注解的相关属性
		if (directPathMatches != null) {
			//分析请求
			addMatchingMappings(directPathMatches, matches, request);
		}
		if (matches.isEmpty()) {
			// No choice but to go through all mappings...
			addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
		}
		// 如果局部matches中元素为空,说明请求头校验失败
		if (!matches.isEmpty()) {
			Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
			matches.sort(comparator);
			Match bestMatch = matches.get(0);
			...
			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);
		}
	}
}

请求头相关参数校验失败抛出的异常包括:HttpRequestMethodNotSupportedExceptionHttpMediaTypeNotSupportedExceptionHttpMediaTypeNotAcceptableExceptionUnsatisfiedServletRequestParameterException

但是这些类型的异常好像不能被全局拦截器拦截处理。

2.1.解析请求头相关属性

核心就是校验请求request中相关属性跟RequestMappingInfo中属性是否匹配。

public abstract class AbstractHandlerMethodMapping<T>  implements InitializingBean {

	private void addMatchingMappings(Collection mappings, List matches, HttpServletRequest request) {
		for (T mapping : mappings) {
			T match = getMatchingMapping(mapping, request);
			if (match != null) {//正常请求校验都通过,最终返回重新包装后的RequestMappingInfo
				matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
			}
		}
	}
}
public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping {
	@Override
	protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
		return info.getMatchingCondition(request);
	}
}

2.1.1、RequestMappingInfo

该类中的相关属性是对 注解@RequestMapping之字段属性的封装。

public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
	public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
		//请求方式: 校验Method属性,即是否为post or get 等相对应的请求方式
		RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
		if (methods == null) {
			return null;
		}
		//请求参数
		ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
		if (params == null) {
			return null;
		}
		//consumer参数:请求头中contentType是否一致。
		HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
		if (headers == null) {
			return null;
		}
		//producer参数:请求头中Accept是否一致
		ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
		if (consumes == null) {
			return null;
		}
		ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
		if (produces == null) {
			return null;
		}
		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());
	}
}

你可能感兴趣的:(java,前端,服务器)