前言

  在介绍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(源码)分析的更多相关文章

  1. Spring之SpringMVC的RequestToViewNameTranslator(源码)分析

    前言 SpringMVC如果在处理业务的过程中发生了异常,这个时候是没有一个完整的ModelAndView对象返回的,它应该是怎么样处理呢?或者说应该怎么去获取一个视图然后去展示呢.下面就是要讲的Re ...

  2. Spring之SpringMVC的Controller(源码)分析

    说明: 例子就不举了,还是直接进入主题,本文主要是以SpringMVC的Controller接口为入点,来分析SpringMVC中C的具体实现和处理过程. 1.Controller接口 public ...

  3. Spring Boot 揭秘与实战 源码分析 - 工作原理剖析

    文章目录 1. EnableAutoConfiguration 帮助我们做了什么 2. 配置参数类 – FreeMarkerProperties 3. 自动配置类 – FreeMarkerAutoCo ...

  4. Spring Boot 揭秘与实战 源码分析 - 开箱即用,内藏玄机

    文章目录 1. 开箱即用,内藏玄机 2. 总结 3. 源代码 Spring Boot提供了很多”开箱即用“的依赖模块,那么,Spring Boot 如何巧妙的做到开箱即用,自动配置的呢? 开箱即用,内 ...

  5. Spring Environment(二)源码分析

    Spring Environment(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Envi ...

  6. SpringMVC由浅入深day01_6源码分析(了解)

    6 源码分析(了解) 通过前端控制器源码分析springmvc的执行过程. 入口 第一步:前端控制器接收请求 调用doDiapatch 第二步:前端控制器调用处理器映射器查找 Handler 第三步: ...

  7. Spring Security(四) —— 核心过滤器源码分析

    摘要: 原创出处 https://www.cnkirito.moe/spring-security-4/ 「老徐」欢迎转载,保留摘要,谢谢! 4 过滤器详解 前面的部分,我们关注了Spring Sec ...

  8. Spring Cloud Eureka服务注册源码分析

    Eureka是怎么work的 那eureka client如何将本地服务的注册信息发送到远端的注册服务器eureka server上.通过下面的源码分析,看出Eureka Client的定时任务调用E ...

  9. spring mvc 启动过程及源码分析

    由于公司开源框架选用的spring+spring mvc + mybatis.使用这些框架,网上都有现成的案例:需要那些配置文件.每种类型的配置文件的节点该如何书写等等.如果只是需要项目能够跑起来,只 ...

随机推荐

  1. sql 学习笔记 档

    从下面的内容 3c   school 1:Sql 它分为两部分: 6 2:查询 7 3:插入: 9 4:数据库更新 UPDATE 9 5:删除 DELETE 10 6:Sql TOP 子句: 10 7 ...

  2. Linux内核进程管理

    介绍: 在Linux的内核的五大组成模块中,进程管理模块时很重要的一部分.它尽管不像内存管理.虚拟文件系统等模块那样复杂.也不像进程间通信模块那样条理化,但作为五大内核模块之中的一个,进程管理对我们理 ...

  3. Install shipyard

    2台机器,192.168.1.153,192.168.1.154 安装Shipyard 1. 154作为集群主节点,在154机器上执行命令 curl -sSL https://shipyard-pro ...

  4. 基于NSIS脚本开发的安装程序制作软件:易量安装

    原文 基于NSIS脚本开发的安装程序制作软件:易量安装 前几天“萝卜”给我推荐了一款安装程序制作工具——易量安装. 易量安装是一款安装程序制作软件,基于著名的NSIS(Nullsoft Scripta ...

  5. Unity3D移动端内存优化(NGUI方面)

     Unity3D引擎技术交流QQ群:[21568554] 做3d移动端内存一直是人们头疼的问题,载入的资源释放了,还有其它的须要释放.比方ngui释放,事实上主要是NGUI的Texture和Spr ...

  6. IntelliJ Idea中一个编译报错引发的

    package verify; public class Verifier { private String name; public Verifier() { this.name = getClas ...

  7. Ubuntu设置交换空间參考教程[图]

    假设你当前使用的Ubuntu系统,不管是虚拟机还是实体机,没有交换分区或交换分区空间不足,能够为其设置交换空间. 本文提供的是一种设置交换空间的简单方法. 如若转载,请注明博文地址及原作者(Risin ...

  8. SSH框架总结(帧分析+环境结构+示例源代码下载)

    首先,SSH不是一个框架.而是多个框架(struts+spring+hibernate)的集成,是眼下较流行的一种Web应用程序开源集成框架,用于构建灵活.易于扩展的多层Web应用程序. 集成SSH框 ...

  9. 带你轻松玩转Git--瞬间创建本地仓库

    在上一篇文章中我们对版本控制有了一个比较宏观的了解,同时也能够看到Git 所处在的历史地位.并且对版本控制系统的体系进行了一个宏观的对比,貌似让读者看起来挺复杂的样子. 笔者将会尽可能的简单向大家分享 ...

  10. 移植X264成功

    http://blog.csdn.net/mashang123456789/article/details/8673426 http://blog.csdn.net/b5w2p0/article/de ...