SpringMVC源码解读 - RequestMapping注解实现解读 - RequestCondition体系
2016-02-23 18:44
453 查看
一般我们开发时,使用最多的还是@RequestMapping注解方式.
台前的是RequestMapping ,正经干活的却是RequestCondition,根据配置的不同条件匹配request.
@RequestMapping注解,请看<SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping初始化>
典型的接口+模板.一个接口ReqeustCondition,一个抽象类,定义基础,然后n多的具体实现.
实现中可以分为3类:基础实现,外观类和容器.
其中CompositeRequestCondition和RequestMappingInfo本身不带任何的匹配条件,只是用于包装其他的RequestCondition进行匹配
基础实现:
consumes对应request的提交内容类型content type,如application/json, text/html
headers 对应http request 的请求头
params对应http request parameter
Patterns对应url,就是注解value中的配置
produces指定返回的内容类型的content type,仅当request请求头中的(Accept)类型中包含该指定类型才返回
requestMethods对应 http method,如GET,POST,PUT,DELETE等
外观类:
RequestConditionHolder,用于不知道具体是RequestCondition哪个子类时.自定义的条件,使用的这个进行封装
容器:
CompositeRequestCondition封装基础实现,具体的匹配都委托给基础实现类.
RequestMappingInfo,对应@RequestMapping注解,一一对应注解内容与基础实现,使用时一一委托.
先来看看RequestCondition的接口定义
老规矩,接下来得上抽象类AbstractRequestCondition
AbstractRequestCondition做的事不多,覆写equals,hashCode,toString.实现equals,hashCode,toString时预留模板方法getContent();实现toString时预留模板方法getToStringInfix().
接下来得看具体实现了,捏不到软柿子,用ParamsRequestCondition简单说明下子类吧
// ParamsRequestCondition
ParamExpression其实很简单,看父类AbstractNameValueExpression很清楚
// AbstractNameValueExpression
到这里我们就可以看懂,使用ParamExpression保存param参数,这样可以任意多个.
combine的实现也就水到渠成,直接把expression拼接到一个集合里就行:
getMatchingCondition时,只要有一个不符合就判定条件不匹配
这边的match方法比较有意思,可以看下
ParamExpression中给出matchName与matchValue的实现.
ParamExpression这里又是接口+抽象实现+模板方法设计模式,偷个懒,暂时不去关心各层抽象的什么.
compareTo根据匹配条件的多少来判定顺序
// ParamsRequestCondition
记得还留有两个模板方法
getContent直接返回记录param的expressions
getToStringInfix则使用&&
// ParamsRequestCondition
再看看是如何解析param的
// ParamsRequestCondition
核心的代码还是在AbstractNameValueExpression
// AbstractNameValueExpression
逻辑不复杂,代码看着有点烦,是不是应该听Martin Fowler在<重构>中的建议,来个extract method?
RequestCondition的解读未完,待续:
SpringMVC源码解读 - RequestMapping注解实现解读 - ConsumesRequestCondition
SpringMVC源码解读 - RequestMapping注解实现解读 - RequestMappingInfo
@RequestMapping(value = "/", param = "role=guest", consumes = "!application/json") public void myHtmlService() { // ... }
台前的是RequestMapping ,正经干活的却是RequestCondition,根据配置的不同条件匹配request.
@RequestMapping注解,请看<SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping初始化>
典型的接口+模板.一个接口ReqeustCondition,一个抽象类,定义基础,然后n多的具体实现.
实现中可以分为3类:基础实现,外观类和容器.
其中CompositeRequestCondition和RequestMappingInfo本身不带任何的匹配条件,只是用于包装其他的RequestCondition进行匹配
基础实现:
consumes对应request的提交内容类型content type,如application/json, text/html
headers 对应http request 的请求头
params对应http request parameter
Patterns对应url,就是注解value中的配置
produces指定返回的内容类型的content type,仅当request请求头中的(Accept)类型中包含该指定类型才返回
requestMethods对应 http method,如GET,POST,PUT,DELETE等
外观类:
RequestConditionHolder,用于不知道具体是RequestCondition哪个子类时.自定义的条件,使用的这个进行封装
容器:
CompositeRequestCondition封装基础实现,具体的匹配都委托给基础实现类.
RequestMappingInfo,对应@RequestMapping注解,一一对应注解内容与基础实现,使用时一一委托.
先来看看RequestCondition的接口定义
package org.springframework.web.servlet.mvc.condition; /** * The contract for request conditions. */ public interface RequestCondition<T> { /** * 将不同的筛选条件合并 */ T combine(T other); /** * 根据request查找匹配到的筛选条件 */ T getMatchingCondition(HttpServletRequest request); /** * 不同筛选条件比较,用于排序 */ int compareTo(T other, HttpServletRequest request); } }
老规矩,接下来得上抽象类AbstractRequestCondition
AbstractRequestCondition做的事不多,覆写equals,hashCode,toString.实现equals,hashCode,toString时预留模板方法getContent();实现toString时预留模板方法getToStringInfix().
package org.springframework.web.servlet.mvc.condition; /** * A base class for {@link RequestCondition} types providing implementations of * {@link #equals(Object)}, {@link #hashCode()}, and {@link #toString()}. * * @author Rossen Stoyanchev * @since 3.1 */ public abstract class AbstractRequestCondition<T extends AbstractRequestCondition<T>> implements RequestCondition<T> { /** * Return the discrete items a request condition is composed of. * For example URL patterns, HTTP request methods, param expressions, etc. * @return a collection of objects, never {@code null} */ protected abstract Collection<?> getContent(); @Override public boolean equals(Object o) { if (this == o) { return true; } if (o != null && getClass().equals(o.getClass())) { AbstractRequestCondition<?> other = (AbstractRequestCondition<?>) o; return getContent().equals(other.getContent()); } return false; } @Override public int hashCode() { return getContent().hashCode(); } @Override public String toString() { StringBuilder builder = new StringBuilder("["); for (Iterator<?> iterator = getContent().iterator(); iterator.hasNext();) { Object expression = iterator.next(); builder.append(expression.toString()); if (iterator.hasNext()) { builder.append(getToStringInfix()); } } builder.append("]"); return builder.toString(); } /** * The notation to use when printing discrete items of content. * For example " || " for URL patterns or " && " for param expressions. */ protected abstract String getToStringInfix(); }
接下来得看具体实现了,捏不到软柿子,用ParamsRequestCondition简单说明下子类吧
// ParamsRequestCondition
// 保存解析出来的param匹配条件 private final Set<ParamExpression> expressions;
ParamExpression其实很简单,看父类AbstractNameValueExpression很清楚
// AbstractNameValueExpression
package org.springframework.web.servlet.mvc.condition; abstract class AbstractNameValueExpression<T> implements NameValueExpression<T> { // 参数的名字 protected final String name; // 参数的值 protected final T value; // 参数的匹配规则,是= 还是!= protected final boolean isNegated; }
到这里我们就可以看懂,使用ParamExpression保存param参数,这样可以任意多个.
combine的实现也就水到渠成,直接把expression拼接到一个集合里就行:
package org.springframework.web.servlet.mvc.condition; public final class ParamsRequestCondition extends AbstractRequestCondition<ParamsRequestCondition> { /** * Returns a new instance with the union of the param expressions * from "this" and the "other" instance. */ public ParamsRequestCondition combine(ParamsRequestCondition other) { Set<ParamExpression> set = new LinkedHashSet<ParamExpression>(this.expressions); set.addAll(other.expressions); return new ParamsRequestCondition(set); } }
getMatchingCondition时,只要有一个不符合就判定条件不匹配
package org.springframework.web.servlet.mvc.condition; public final class ParamsRequestCondition extends AbstractRequestCondition<ParamsRequestCondition> { /** * Returns "this" instance if the request matches all param expressions; * or {@code null} otherwise. */ public ParamsRequestCondition getMatchingCondition(HttpServletRequest request) { for (ParamExpression expression : expressions) { if (!expression.match(request)) { return null; } } return this; } }
这边的match方法比较有意思,可以看下
package org.springframework.web.servlet.mvc.condition; abstract class AbstractNameValueExpression<T> implements NameValueExpression<T> { public final boolean match(HttpServletRequest request) { boolean isMatch; if (this.value != null) { isMatch = matchValue(request); } else { // 没有value时,只要匹配name就好 isMatch = matchName(request); } return isNegated ? !isMatch : isMatch; // 这边需要看仔细,=与!=的处理 } protected abstract boolean matchName(HttpServletRequest request); protected abstract boolean matchValue(HttpServletRequest request); }
ParamExpression中给出matchName与matchValue的实现.
ParamExpression这里又是接口+抽象实现+模板方法设计模式,偷个懒,暂时不去关心各层抽象的什么.
compareTo根据匹配条件的多少来判定顺序
// ParamsRequestCondition
public int compareTo(ParamsRequestCondition other, HttpServletRequest request) { return other.expressions.size() - this.expressions.size(); }
记得还留有两个模板方法
getContent直接返回记录param的expressions
getToStringInfix则使用&&
// ParamsRequestCondition
@Override protected Collection<ParamExpression> getContent() { return expressions; } @Override protected String getToStringInfix() { return " && "; }
再看看是如何解析param的
// ParamsRequestCondition
/** * Create a new instance from the given param expressions. * @param params expressions with syntax defined in {@link RequestMapping#params()}; * if 0, the condition will match to every request. */ public ParamsRequestCondition(String... params) { this(parseExpressions(params)); } private static Collection<ParamExpression> parseExpressions(String... params) { Set<ParamExpression> expressions = new LinkedHashSet<ParamExpression>(); if (params != null) { for (String param : params) { expressions.add(new ParamExpression(param)); } } return expressions; }
核心的代码还是在AbstractNameValueExpression
// AbstractNameValueExpression
逻辑不复杂,代码看着有点烦,是不是应该听Martin Fowler在<重构>中的建议,来个extract method?
AbstractNameValueExpression(String expression) { int separator = expression.indexOf('='); if (separator == -1) { this.isNegated = expression.startsWith("!"); this.name = isNegated ? expression.substring(1) : expression; this.value = null; } else { this.isNegated = (separator > 0) && (expression.charAt(separator - 1) == '!'); this.name = isNegated ? expression.substring(0, separator - 1) : expression.substring(0, separator); this.value = parseValue(expression.substring(separator + 1)); } }
RequestCondition的解读未完,待续:
SpringMVC源码解读 - RequestMapping注解实现解读 - ConsumesRequestCondition
SpringMVC源码解读 - RequestMapping注解实现解读 - RequestMappingInfo
相关文章推荐
- iOS开发-加密与解密之CommonCrypto与Security.framework
- 获得activity的类名
- Socket通信,Android,java
- Android Studio NDK使用
- iOS所有框架总览与介绍
- iOS/OS X 内存管理(二):借助工具解决内存问题
- iOS动画开发之——炫酷的粒子效果
- Android查看SHA1值
- IOS开发中的几种设计模式介绍
- IOS开发证书显示“此证书的签发者无效”解决方法
- 运行app时报java.lang.ClassNotFoundException
- iOS小明开发笔记(二十一) (缓存机制NSUserDefaults)
- Android 三大图片缓存原理、特性对比
- 全屏背景-Quick-cocos2dx
- iOS小明开发笔记(二十) (retain、strong、weak、assign区别)
- Android Service与IntentService区别
- iOS 几种常见的数据储存方式
- iOS小明开发笔记(十九) (Mac 终端命令介绍)
- 25.iOS中集合遍历方法的比较和技巧
- swift部分控件学习 源码集合