您的位置:首页 > 编程语言 > Java开发

Spring之SpringMVC的MethodNameResolver(源码)分析

2015-11-06 07:44 453 查看

前言

  在介绍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的实现中采用了模板设计模式一样。如果自己能够灵活应用这些设计模式,并且有个很好的思想,我想写出这样优秀的代码应该也不是问题,加油,共勉。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: