SpringMVC之RequestMappingHandlerMapping
Posted 木叶之荣
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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是怎么处理的呢?
以上是关于SpringMVC之RequestMappingHandlerMapping的主要内容,如果未能解决你的问题,请参考以下文章
springmvc学习笔记-springmvc整合mybatis之controller
springmvc学习笔记-springmvc整合mybatis之service
springmvc学习笔记(11)-springmvc注解开发之简单参数绑定