SpringMVC之RequestMappingHandlerMapping(三)

我们在这篇文章中接着上一篇文章的内容接着说,我们在上一篇文章中说到在doWithMethods这个方法中会调用MethodCallback的doWith方法进行方法处理,那么我们在RequestMappingHandlerMapping中MethodCallback的实现是什么呢?

			ReflectionUtils.doWithMethods(currentHandlerType, 
			//下面的这一段代码就是MethodCallback的实现
			method -> {
				//获取真正的方法 因为这个方法可能会是接口的default
				Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
				//这个地方又是一个回调的方法 真正的解析RequestHandlerMapping的地方
				T result = metadataLookup.inspect(specificMethod);
				if (result != null) {
				//这里是寻找桥接方法,如果没有桥接方法,则返回本方法
					Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
					if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
						//这里是放到methodMap中,key是Method 在Method中重写里equals和hashcode方法
						methodMap.put(specificMethod, result);
					}
				}
			}
			, ReflectionUtils.USER_DECLARED_METHODS);

metadataLookup.inspect调用的是getMappingForMethod这个方法。

	Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
					(MethodIntrospector.MetadataLookup<T>) method -> {
						try {
							//	metadataLookup.inspect调用的是这个方法
							return getMappingForMethod(method, userType);
						}
						catch (Throwable ex) {
							throw new IllegalStateException("Invalid mapping on handler class [" +
									userType.getName() + "]: " + method, ex);
						}
					});

我们把上面的过程做一个简单的总结:看着前面的代码很复杂,其实做的事情很简单。我们首先先查找到带有Controller或者RequestMapping注解的类,然后遍历这个类和它的父类的所有方法以及它们所实现的接口中的default方法,然后把得到的方法调用getMappingForMethod方法进行解析。

	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
		//根据Method获取RequestMappingInfo
		RequestMappingInfo info = createRequestMappingInfo(method);
		if (info != null) {
			//根据Class获取RequestMappingInfo
			RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
			if (typeInfo != null) {
				//进行合并
				info = typeInfo.combine(info);
			}
			String prefix = getPathPrefix(handlerType);
			if (prefix != null) {
				info = RequestMappingInfo.paths(prefix).build().combine(info);
			}
		}
		return info;
	}
	private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
		//这里是根据Method获取RequestMapping注解的信息
		//这里卖个关子,如果我们的Controller的method上面没有直接写RequestMapping相关的注解
		//而是在他的接口上写了RequestMapping相关的信息,如我们使用SpringCloud进行为服务开发
		//那么Controller的method是怎么获取到RequestMapping相关的信息的呢???
		RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
		//这里的RequestCondition是用来给实现着自定义实现用的 基本上不会用到
		RequestCondition<?> condition = (element instanceof Class ?
				getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
		return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
	}

createRequestMappingInfo方法

	protected RequestMappingInfo createRequestMappingInfo(
			RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
		//这里用到了一个典型的建造者模式
		RequestMappingInfo.Builder builder = RequestMappingInfo
				//这里对路径进行解析,在path中是支持SpEL表达式的,
				//RequestMappingHandlerMapping实现了EmbeddedValueResolverAware这个接口
				.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();
	}
		@Override
		public RequestMappingInfo build() {
		//内容协商管理器 有什么用呢? 如果我们的请求是.json结尾的则返回json数据
		//如果我们的请求是.xml结尾的则返回xml格式的数据。
			ContentNegotiationManager manager = this.options.getContentNegotiationManager();
			//构建了一个PatternsRequestCondition对象
			PatternsRequestCondition patternsCondition = new PatternsRequestCondition(
					this.paths, this.options.getUrlPathHelper(), this.options.getPathMatcher(),
					this.options.useSuffixPatternMatch(), this.options.useTrailingSlashMatch(),
					this.options.getFileExtensions());
			//从这里我们可以看到RequestMappingHandlerMapping中的每一个属性都被封装成了一个对应的处理类,典型的单一职责的体现
			return new RequestMappingInfo(this.mappingName, patternsCondition,
					new RequestMethodsRequestCondition(this.methods),
					new ParamsRequestCondition(this.params),
					new HeadersRequestCondition(this.headers),
					new ConsumesRequestCondition(this.consumes, this.headers),
					new ProducesRequestCondition(this.produces, this.headers, manager),
					this.customCondition);
		}

我们为上面的代码写个小总结,我们在method上添加的RequestMapping的信息都被解析成了RequestMappingInfo这个类,并且每一个属性值都对应一个处理类。他们都实现了RequestCondition这个接口。我们的RequestMapping注解可以写在方法上,也可以写在Controller类上,如果我们同时在Controller类和method上都添加类RequestMapping注解,那么Spring MVC是怎么处理的呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值