每篇一句
你的工作效率高,老板会认为你强度不够。你代码bug多,各种生产环境救火,老板会觉得你是团队的核心成员。
前言
在享受Spring MVC
带给你便捷的时候,你是否曾经这样疑问过:Controller
的handler
方法参数能够自动完成封装(有时即使没有@PathVariable
、@RequestParam
、@RequestBody
等注解都可),甚至在方法参数任意位置写HttpServletRequest
、HttpSession
、Writer
...等类型的参数,它自动就有值了便可直接使用。
对此你是否想问一句:Spring MVC
它是怎么办到的?那么本文就揭开它的神秘面纱,还你一片"清白"。
Spring MVC
作为一个最为流行的web框架,早早已经成为了实际意义上的标准化(框架),特别是随着Struts2
的突然崩塌,Spring MVC
几乎一骑绝尘,因此深入了解它有着深远的意义
Spring MVC
它只需要区区几个注解就能够让一个普通的java方法成为一个Handler
处理器,并且还能有自动参数封装、返回值视图处理/渲染等一系列强大功能,让coder的精力更加的聚焦在自己的业务。
像JSF、Google Web Toolkit、Grails Framework等web框架至少我是没有用过的。
这里有个轻量级的web框架:Play Framework
设计上我个人觉得还挺有意思,有兴趣的可以玩玩
HandlerMethodArgumentResolver
策略接口:用于在给定请求的上下文中将方法参数解析为参数值。简单的理解为:它负责处理你Handler
方法里的所有入参:包括自动封装、自动赋值、校验等等。有了它才能会让Spring MVC
处理入参显得那么高级、那么自动化。
Spring MVC
内置了非常非常多的实现,当然若还不能满足你的需求,你依旧可以自定义和自己注册,后面我会给出自定义的示例。
有个形象的公式:HandlerMethodArgumentResolver = HandlerMethod + Argument(参数) + Resolver(解析器)
。
解释为:它是HandlerMethod
方法的解析器,将HttpServletRequest(header + body 中的内容)
解析为HandlerMethod
方法的参数(method parameters)
// @since 3.1 HandlerMethod 方法中 参数解析器
public interface HandlerMethodArgumentResolver {
// 判断 HandlerMethodArgumentResolver 是否支持 MethodParameter
// (PS: 一般都是通过 参数上面的注解|参数的类型)
boolean supportsParameter(MethodParameter parameter);
// 从NativeWebRequest中获取数据,ModelAndViewContainer用来提供访问Model
// MethodParameter parameter:请求参数
// WebDataBinderFactory用于创建一个WebDataBinder用于数据绑定、校验
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
基于这个接口的处理器实现类不可谓不丰富,非常之多。我截图如下:
因为子类众多,所以我分类进行说明。我把它分为四类进行描述:
- 基于
Name
- 数据类型是
Map
的 - 固定参数类型
- 基于
ContentType
的消息转换器
第一类:基于Name
从URI(路径变量)、HttpServletRequest、HttpSession、Header、Cookie...等中根据名称key来获取值
这类处理器所有的都是基于抽象类AbstractNamedValueMethodArgumentResolver
来实现,它是最为重要的分支(分类)。
// @since 3.1 负责从路径变量、请求、头等中拿到值。(都可以指定name、required、默认值等属性)
// 子类需要做如下事:获取方法参数的命名值信息、将名称解析为参数值
// 当需要参数值时处理缺少的参数值、可选地处理解析值
//特别注意的是:默认值可以使用${}占位符,或者SpEL语句#{}是木有问题的
public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Nullable
private final ConfigurableBeanFactory configurableBeanFactory;
@Nullable
private final BeanExpressionContext expressionContext;
private final Map<MethodParameter, NamedValueInfo> namedValueInfoCache = new ConcurrentHashMap<>(256);
public AbstractNamedValueMethodArgumentResolver() {
this.configurableBeanFactory = null;
this.expressionContext = null;
}
public AbstractNamedValueMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) {
this.configurableBeanFactory = beanFactory;
// 默认是RequestScope
this.expressionContext = (beanFactory != null ? new BeanExpressionContext(beanFactory, new RequestScope()) : null);
}
// protected的内部类 所以所有子类(注解)都是用友这三个属性值的
protected static class NamedValueInfo {
private final String name;
private final boolean required;
@Nullable
private final String defaultValue;
public NamedValueInfo(String name, boolean required, @Nullable String defaultValue) {
this.name = name;
this.required = required;
this.defaultValue = defaultValue;