Spring之SpringMVC的MethodNameResolver(源码)分析
前言
在介绍SpringMVC 的Controller的具体实现中,我们讲到了MultiActionController。在获取处理请求对于的方法的时候我们用到了下面的代码,来自于MultiActionController的handleRequestInternal的方法:
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
try {
String methodName = this.methodNameResolver.getHandlerMethodName(request);
return invokeNamedMethod(methodName, request, response);
}
catch (NoSuchRequestHandlingMethodException ex) {
return handleNoSuchRequestHandlingMethod(ex, request, response);
}
}
MultiActionController通过methodNameResolver的getHandlerMethodName()方法获取处理该请求的具体方法名字。来看下methodNameResolver具体实现。
1.MethodNameResolver介绍
MethodNameResolver是个接口,来看看定义
public interface MethodNameResolver { String getHandlerMethodName(HttpServletRequest request) throws NoSuchRequestHandlingMethodException; }
这个接口用于MultiActionController方法中获取具体的参数,它是通过策略模式来实现的。它可以通过具体的请求映射到处理的方法名上,他们的改变也不会影响到其他应用程序。看看下面其他的具体实现。MethodNameResolver的实现类包括ParameterMethodNameResolver、AbstractUrlMethodNameResolver、InternalPathMethodNameResolver、PropertiesMethodNameResolver。
2.ParameterMethodNameResolver
ParameterMethodNameResolver实现了MethodNameResolver接口,它支持通过参数值来映射到方法名上。通过注释知道可以通过下面的过程来获取具体的方法:
1.根据请求的参数名解析功能方法名;
2.根据请求参数名的值解析功能方法名,默认的参数名是 action,即请求的参数中含有“action=query” ,则功能处理方法名为 query;
3.逻辑功能方法名到真实功能方法名映射;
4.默认的方法名,当以上策略失败时默认调用的方法名。
来具体获取处理器方法名过程:
{
String methodName = null; // 检查参数名是否存在
if (this.methodParamNames != null) {
for (String candidate : this.methodParamNames) {
if (WebUtils.hasSubmitParameter(request, candidate)) {
methodName = candidate;
if (logger.isDebugEnabled()) {
logger.debug("Determined handler method '" + methodName +
"' based on existence of explicit request parameter of same name");
}
break;
}
}
} // 检查参数名的值是否存在
if (methodName == null && this.paramName != null) {
methodName = request.getParameter(this.paramName);
if (methodName != null) {
if (logger.isDebugEnabled()) {
logger.debug("Determined handler method '" + methodName +
"' based on value of request parameter '" + this.paramName + "'");
}
}
} if (methodName != null && this.logicalMappings != null) {
// Resolve logical name into real method name, if appropriate.
String originalName = methodName;
methodName = this.logicalMappings.getProperty(methodName, methodName);
if (logger.isDebugEnabled()) {
logger.debug("Resolved method name '" + originalName + "' to handler method '" + methodName + "'");
}
} if (methodName != null && !StringUtils.hasText(methodName)) {
if (logger.isDebugEnabled()) {
logger.debug("Method name '" + methodName + "' is empty: treating it as no method name found");
}
methodName = null;
} if (methodName == null) {
if (this.defaultMethodName != null) {
// No specific method resolved: use default method.
methodName = this.defaultMethodName;
if (logger.isDebugEnabled()) {
logger.debug("Falling back to default handler method '" + this.defaultMethodName + "'");
}
}
else {
// If resolution failed completely, throw an exception.
throw new NoSuchRequestHandlingMethodException(request);
}
} return methodName;
}
3、PropertiesMethodNameResolver
PropertiesMethodNameResolver和InternalPathMethodNameResolver继承了抽象类AbstractUrlMethodNameResolver。而AbstractUrlMethodNameResolver提供了方法名的获取的方法。
public final String getHandlerMethodName(HttpServletRequest request)
throws NoSuchRequestHandlingMethodException { String urlPath = this.urlPathHelper.getLookupPathForRequest(request);
String name = getHandlerMethodNameForUrlPath(urlPath);
if (name == null) {
throw new NoSuchRequestHandlingMethodException(urlPath, request.getMethod(), request.getParameterMap());
}
if (logger.isDebugEnabled()) {
logger.debug("Returning handler method name '" + name + "' for lookup path: " + urlPath);
}
return name;
}
由上面的代码可知,子类的差异在于 String name = getHandlerMethodNameForUrlPath(urlPath);这段代码getHandlerMethodNameForUrlPath是抽象方法,具体的实现见子类。首先看下PropertiesMethodNameResolver的getHandlerMethodNameForUrlPath的实现:
PropertiesMethodNameResolver提供自定义的从请求 URL 解析功能方法的方法名,使用一组用户自定义的模式到功能方法名的映射,映射使用 Properties 对象存放,
protected String getHandlerMethodNameForUrlPath(String urlPath) {
String methodName = this.mappings.getProperty(urlPath);
if (methodName != null) {
return methodName;
}
Enumeration propNames = this.mappings.propertyNames();
while (propNames.hasMoreElements()) {
String registeredPath = (String) propNames.nextElement();
if (this.pathMatcher.match(registeredPath, urlPath)) {
return (String) this.mappings.get(registeredPath);
}
}
return null;
}
用法如下:
<bean id="propertiesMethodNameResolver"
class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
<property name="mappings">
<props>
<prop key="/create">create</prop>
<prop key="/update">update</prop>
<prop key="/delete">delete</prop>
<prop key="/list">list</prop>
<!-- 默认的行为 -->
<prop key="/**">list</prop>
</props>
</property>
</bean>
4.InternalPathMethodNameResolver
InternalPathMethodNameResolver是MethodNameResolver的默认实现,在MultiActionController中的MethodNameResolver的初始化可知,
private MethodNameResolver methodNameResolver = new InternalPathMethodNameResolver()
这个解析器提供从请求 URL 路径解析处理器方法的方法名,从请求的最后一个路径(/)开始,并忽略扩展名;如请求 URL 是“/user/list.html” ,则解析的功能处
理方法名为“list” ,即调用 list 方法。该解析器还可以指定前缀和后缀,通过 prefix 和 suffix 属性来判断。下面就是详细的getHandlerMethodName方法的实现过程。
public final String getHandlerMethodName(HttpServletRequest request)
throws NoSuchRequestHandlingMethodException { String urlPath = this.urlPathHelper.getLookupPathForRequest(request);
String name = getHandlerMethodNameForUrlPath(urlPath);
if (name == null) {
throw new NoSuchRequestHandlingMethodException(urlPath, request.getMethod(), request.getParameterMap());
}
if (logger.isDebugEnabled()) {
logger.debug("Returning handler method name '" + name + "' for lookup path: " + urlPath);
}
return name;
}
5.总结说明
MethodNameResolver 的实现是通过策略模式来的,通过这个也可以是发现,Spring的实现中大量采用了设计模式的相关知识,如果Controller的实现中采用了模板设计模式一样。如果自己能够灵活应用这些设计模式,并且有个很好的思想,我想写出这样优秀的代码应该也不是问题,加油,共勉。
Spring之SpringMVC的MethodNameResolver(源码)分析的更多相关文章
- Spring之SpringMVC的RequestToViewNameTranslator(源码)分析
前言 SpringMVC如果在处理业务的过程中发生了异常,这个时候是没有一个完整的ModelAndView对象返回的,它应该是怎么样处理呢?或者说应该怎么去获取一个视图然后去展示呢.下面就是要讲的Re ...
- Spring之SpringMVC的Controller(源码)分析
说明: 例子就不举了,还是直接进入主题,本文主要是以SpringMVC的Controller接口为入点,来分析SpringMVC中C的具体实现和处理过程. 1.Controller接口 public ...
- Spring Boot 揭秘与实战 源码分析 - 工作原理剖析
文章目录 1. EnableAutoConfiguration 帮助我们做了什么 2. 配置参数类 – FreeMarkerProperties 3. 自动配置类 – FreeMarkerAutoCo ...
- Spring Boot 揭秘与实战 源码分析 - 开箱即用,内藏玄机
文章目录 1. 开箱即用,内藏玄机 2. 总结 3. 源代码 Spring Boot提供了很多”开箱即用“的依赖模块,那么,Spring Boot 如何巧妙的做到开箱即用,自动配置的呢? 开箱即用,内 ...
- Spring Environment(二)源码分析
Spring Environment(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Envi ...
- SpringMVC由浅入深day01_6源码分析(了解)
6 源码分析(了解) 通过前端控制器源码分析springmvc的执行过程. 入口 第一步:前端控制器接收请求 调用doDiapatch 第二步:前端控制器调用处理器映射器查找 Handler 第三步: ...
- Spring Security(四) —— 核心过滤器源码分析
摘要: 原创出处 https://www.cnkirito.moe/spring-security-4/ 「老徐」欢迎转载,保留摘要,谢谢! 4 过滤器详解 前面的部分,我们关注了Spring Sec ...
- Spring Cloud Eureka服务注册源码分析
Eureka是怎么work的 那eureka client如何将本地服务的注册信息发送到远端的注册服务器eureka server上.通过下面的源码分析,看出Eureka Client的定时任务调用E ...
- spring mvc 启动过程及源码分析
由于公司开源框架选用的spring+spring mvc + mybatis.使用这些框架,网上都有现成的案例:需要那些配置文件.每种类型的配置文件的节点该如何书写等等.如果只是需要项目能够跑起来,只 ...
随机推荐
- C++它 typedef void *HANDLE
阅读时编写代码的代码,经常看到一个代码: typedef void *HANDLE ,这是它背后的故事?怎么理解呢? 不明白的时候.这是非常美妙的感觉,后来我才知道这,这是typedef定义,就在vo ...
- XeTeX中文解决方案(temp)
临时记录一下XeTeX的中文解决方案.一些包的文档只是走马观花得到的解决方法,所以可能有诸多纰漏. 另个人还是比较看好LuaTeX,但是在里边鼓捣中文还是一团糟,等探索一下再回来补充. 我使用的包是x ...
- ASP.NET MVC:Razor 引入命名空间
原文:ASP.NET MVC:Razor 引入命名空间 页面中引用 c# @using MvcApplication83.Models @using MvcApplication83.Common 行 ...
- express: command not found.
npm install -g express 可是不行.全局模式不行. With the release of Express 4.0.0 it looks like you need to do s ...
- ORA-07445: :一个意料之外的问题发生了 核心转储 [ldxsnf()+625] [SIGSEGV
ALERT登录错误消息: Mon Jan 20 15:03:22 2014 Incremental checkpoint up to RBA [0x442f.abd.0], current log t ...
- DevExpress XtraReports 入门四 创建 Web 报表
原文:DevExpress XtraReports 入门四 创建 Web 报表 本文只是为了帮助初次接触或是需要DevExpress XtraReports报表的人群使用的,为了帮助更多的人不会像我这 ...
- POJ 1742 Coins (多重背包)
Coins Time Limit: 3000MS Memory Limit: 30000K Total Submissions: 28448 Accepted: 9645 Descriptio ...
- Android发展的一个重要方面Makefile分析
Android发展的一个重要方面Makefile分析 随着移动互联网的发展,移动开发也越来越吃香了.眼下最火的莫过于android.android是什么就不用说了,android自从开源以来,就受到非 ...
- NET动态调用WebService
NET动态调用WebService 这不是一篇教你了解WebService的博文,也不是对WebService的深入理解, 这是一篇教你在开发过程中,如果动态的调用WebService一个方法. 在比 ...
- 软件project(十)——软件维护
软件维护是软件开发的最长的阶段之一,的精力和费用也是最多的一个阶段,基本上软件交付之后就进入了维护阶段,占整个系统生存周期的40%~70%. 导图: 软件系统并非一成不变的.有时候我们 ...