每篇一句
每当你把事情往外推的时候,你也是在把机会往外推
前言
如果说理解了HandlerMapping
相当于掌握了Spring MVC
的1/3,那么若你继续理解了HandlerAdapter
(以及它的相关组件),那几乎可以说你就理解了它剩下的2/3了。
个人夸张划分,不喜勿喷
HandlerAdapter的作用:因为Spring MVC
中的Handler
可以是多种/4种形式,但是Servlet
需要的处理方法的结构却是固定的,都是以request
和response
为方法入参,那么如何让固定的Servlet
处理方法调用灵活的Handler
来进行处理呢?这就是HandlerAdapter
要做的事情–> 适配。
它的作用是:根据 Handler 来找到支持它的
HandlerAdapter
,通过HandlerAdapter
执行这个Handler
得到ModelAndView
对象。
适配器模式简介
假如你有现在存在一个类的接口方法,但是这个接口不太符合你的预期(方法签名对应不上),如果要用他就需要在他的源码上进行一些修改,显然这个不可行。
这时还有一种方案:你可以做一个适配器,在不修改原来这个接口源码的情况下,在适配器上对这个接口进行运用,使得适配器符合你的接口规范。
其实生活上适配器有大量的应用,最为常见的就是电源适配器吧~
适配器模式(Adapter Pattern)
:把一个类的接口变换成客户所期待的另一种接口, Adapter模式使原本因接口不匹配(或者不兼容)而无法在一起工作的两个类能够在一起工作。
适配器模式又称为转换器模式、变压器模式、包装(Wrapper)器模式(把已有的一些类包装起来,使之能有满足需要的接口)。
以下情况可以使用适配器模式
- 你想使用一个已经存在的类,而它的接口不符合你的需求(但你又不能修改器源码)
- 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作
HandlerAdapter
就是利用适配器模式的一个实现,它在Spring MVC
体系中的地位举足轻重。
HandlerAdapter
中文释义:Handler
的适配器。JavaDoc解释为:MVC框架SPI,允许核心MVC工作流的参数化。
它必须为每个Handler
程序都准备一个对应的适配器来处理请求,有了这个SPI
接口,它能够让DispatcherServlet
无限的扩展:能够兼容一切的Handler
处理器类型。
DispatcherServlet
就是通过这个接口来访问handler
的,而不是直接去访问真正的实际的处理器,这样做的好处是大大的:
- 处理器程序允许是任意的Object
- 集成第三方请求处理器的时候,本处代码也无需修改
此接口不适用于应用程序开发人员。对于想要开发自己的web工作流的处理程序来说(或者你想进行深度定制),那就用它吧。
为何需要使用HandlerAdapter适配?
Spring MVC
的Handler
(Controller接口,HttpRequestHandler,Servlet、@RequestMapping)有四种表现形式,在Handler
不确定是什么方式的时候(可能是方法、也可能是类),适配器这种设计模式就能模糊掉具体的实现,从而就能提供统一访问接口。
public interface HandlerAdapter {
// 判断当前的这个HandlerAdapter 是否 支持给与的handler
// 因为一般来说:每个适配器只能作用于一种处理器(你总不能把手机适配器拿去用于电脑吧)
boolean supports(Object handler);
// 核心方法:利用 Handler 处理请求,然后返回一个ModelAndView
// DispatcherServlet最终就是调用此方法,来返回一个ModelAndView的~
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
// 同HttpServlet 的 getLastModified方法
// Can simply return -1 if there's no support in the handler class.
long getLastModified(HttpServletRequest request, Object handler);
}
HandlerAdapter.supports()
HandlerAdapter.supports()
方法的主要作用在于判断当前的HandlerAdapter是否能够支持当前的handler的适配。这里的handler是由HandlerExecutionChain HandlerMapping.getHandler(HttpServletRequest)
方法获取到的。从这里可以看出:
HandlerMapping
的作用主要是根据request请求匹配/映射上能够处理当前request的handlerHandlerAdapter
的作用在于将request中的各个属性,如request param
适配为handler能够处理的形式
- 参数绑定、数据校验、内容协商…几乎所有的web层问题都在在这里完成的。
HandlerAdapter.handle()
执行真正开发者开发的处理方法的地方。Spring MVC
自动帮我们完成数据绑定、视图渲染等等一切周边工作~
HandlerAdapter.getLastModified()
获取当前请求的最后更改时间,主要用于供给浏览器判断当前请求是否修改过,从而判断是否可以直接使用之前缓存的结果
它的继承树:
从实现类的个数上看是不是很熟悉:4个,刚好对应着我们
Handler
内置的那四种实现方式~
由简到繁,逐个分析:
SimpleControllerHandlerAdapter
适配org.springframework.web.servlet.mvc.Controller
这种Handler。它是一个非常古老的适配器(几乎已弃用状态):
Controller
它没有对参数的自动封装、校验等一系列高级功能,但是它保留有对ModelAndView
的处理能力,这是区别Servlet
这种处理器的地方。
// 适配`org.springframework.web.servlet.mvc.Controller`这种Handler
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
// 最终执行逻辑的还是Handler啊~~~~
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
// 此处注意:若处理器实现了`LastModified`接口,那就委托给它了
// 否则返回-1 表示不要缓存~
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
源码非常之简单,因为它直接处理的就是源生的HttpServletRequest
和HttpServletResponse
,所以它和Servlet
容器是强绑定的。无数据自动封装、校验等一系列高级功能,所以实际应用中此种方式很少被使用。
画外音:Spring5.0后的WebFlux基于Reactive模式是不支持这种Handler的~
HttpRequestHandlerAdapter
适配org.springframework.web.HttpRequestHandler
这种Handler。它比Controller
方式还源生:
// @since 2.0
public class HttpRequestHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {\
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
和上面的唯一不同是:return null
。那是因为HttpRequestHandler#handleRequest()
它没有返回值(全靠开发者自己写response),而Controller
最起码来说还有Model
和View
自动渲染的能力嘛~
SimpleServletHandlerAdapter
适配javax.servlet.Servlet
这种Handler。
public class SimpleServletHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof Servlet);
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
((Servlet) handler).service(request, response);
return null;
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
return -1;
}
}
javax.servlet.Servlet
的处理方式几乎同HttpRequestHandler
,都是对源生请求进行直接处理。它的特殊之处在于:Spring MVC
默认并不向容器注册这种HandlerAdapter,若需要使用是需要调用者手动给注册这个Bean
,Servlet
这种Handler
才能正常使用的~
AbstractHandlerMethodAdapter
从命名中其实就可以看出端倪,它主要是支持到了org.springframework.web.method.HandlerMethod
这种处理器,显然这种处理器也是我们最最最最为常用的。
// @since 3.1 @RequestMapping注解是Spring2.5出现的
// 注意:它实现了Ordered接口
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
// 唯一构造函数。传的false表示:忽略掉supportedMethods这个属性
// 默认它的值是GET、POST、HEAD(见WebContentGenerator)
public AbstractHandlerMethodAdapter() {
// no restriction of HTTP methods by default
super(false);
}
// 只处理HandlerMethod 类型的处理器。抽象方法supportsInternal默认返回true
// 是流出的钩子可以给你自己扩展的
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
// 抽象方法交给子类handleInternal去实现
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
...
}
它有个大名鼎鼎的子类:RequestMappingHandlerAdapter
。此子类已经把HandlerMethod
的实现精确到了@RequestMapping
注解方案。这个HandlerAdapter
可谓是Spring MVC
的精华之所在,只要理解了它以及它的相关组件,就基本可以自信地说自己掌握了Spring MVC
。
因为这部分内容过于复杂繁多,因此我撰了专文来描述它,详情请点击这里
DispatcherServlet#doDispatch分发流程
主要看看DispatcherServlet
是如何使用HandlerAdapter
的。
DispatcherServlet:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
//1、根据URL(当然不一定非得是URL)匹配到一个处理器
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// 若匹配不到Handler处理器,就404了
noHandlerFound(processedRequest, response);
return;
}
//2、从Chain里拿出Handler(注意是Object类型哦~ )然后找到属于它的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
//3、执行作用在此Handler上的所有拦截器的Pre方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//4、真正执行handle方法(也就是你自己书写的逻辑方法),得到一个ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//5、视图渲染
applyDefaultViewName(processedRequest, mv);
//6、执行拦截器的post方法(可见它是视图渲染完成了才会执行的哦~)
mappedHandler.applyPostHandle(processedRequest, response, mv);
...
//7、执行拦截器的afterCompletion方法(不管抛出与否)
}
从执行步骤中可以看到:HandlerAdapter
对于执行流程的通用性起到了非常重要的作用,它能把任何一个处理器(Object)都适配成一个HandlerAdapter
,从而可以做统一的流程处理,这也是为何DispatcherServlet
它能作为其它web处理框架的分发器的原因(因为它没有耦合具体的处理器,你完全可以自己去实现)~
相关阅读
web九大组件之—RequestMappingHandlerAdapter详尽解析【享学Spring MVC】
总结
本文介绍Spring MVC
在处理请求时使用的适配器模式实践HandlerAdapter
,感受到了它对DispatcherServlet
的重要性。适配器模式在基础框架设计中属常用的一种方式,比如Spring AOP
中也有用到,具体请理解我上面说的两个使用场景。
本文留下一个最最最为重要的子类RequestMappingHandlerAdapter
没有放在本文讲述,只因为它过于重要和复杂,请务必出门左拐详细了解下它,传送门在此。