前言
上回我们知道,SpringMVC有九大组件。今天我们聊聊负责Handler调用的HandlerAdapter。
Handler
在讨论HandlerAdapter之前,我们需要先看看明白什么是Handler。Handler在SpringMVC中,可以说是一个逻辑概念。这或许也是他没有出现在官方的Special Bean Types章节中的原因吧。他的作用就是,用来处理特定请求。
在5.3.22版本中,共有5种Handler。
-
Controller接口
是的,你没有看错,SpringMVC有专门的Contorller接口。不过他年纪有点大。是最早的接口,那个年代他还用来对标Struts的Action@FunctionalInterface public interface Controller { @Nullable ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception; }
-
Servlet
没错,Servlet也可以作为DispatcherServlet的Handler的。这样的话,tomcat是不知道这个Servlet的,也不需要在web.xml中配置。另外,如果想要保持对自身的声明周期函数的调用,对ServletContext的感知和联系,则需要额外声明一个后置处理器SimpleServletPostProcessor。
他也是早期SpringMVC的Handlerpublic interface Servlet { void init(ServletConfig var1) throws ServletException; ServletConfig getServletConfig(); void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException; String getServletInfo(); void destroy(); }
-
HttpRequestHandler
@FunctionalInterface public interface HttpRequestHandler { void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException; }
眼尖的同学可能看出来了,相比于Controller接口,他没有返回值。从这点看,他的作用应该和Servlet差不多。Controller可以选择自己通过response完成请求,返回null。也可以返回一个视图对象,交给DispatcherServlet继续执行后续的视图逻辑。但是HttpRequestHandler则只能自己处理请求,因此这点跟Servlet是很相似的。
另外,他是SpringMVC 2.0的产物。 -
HandlerFunction
他是SpringMVC最近的新生儿,于5.2版本才出现的。
不知道大家有没有发现Spring推出了WebFlux(响应式web框架),流式编程看起来就很高大上。而实现流式编程依赖于ReactiveX,而ReactiveX会将模板代码进行封装,这就有函数式编程。搭载上Java8的lambda表达式,高大上的感觉就来了嘛。而HandlerFunction就是为了在SpringMVC也能用上这么高大上的功能引入了。@FunctionalInterface public interface HandlerFunction<T extends ServerResponse> { /** * Handle the given request. * @param request the request to handle * @return the response */ T handle(ServerRequest request) throws Exception; }
详细介绍大家可以看官方文档,这里不扩展了,不是我们的重点。
webmvc-fn-overview -
@Controller/@RequestMapping
带有@Controller/@RequestMapping注解的对象都是Handler。这个也不用多说,大家应该都是使用@Controller搭配@RequestMapping来声明接口的。这里当然包括他们的派生注解@RestController@GetMapping@PostMapping等。就不多说了。PS: @RequestMapping可以在类上注解,大家知道吧。但是如果不带@Controller,而是@Component,那么这个类同样也会被识别为Handler的。
HandlerMethod
不知道大家有没有发现@Controller这种handler比较特别,可以处理多个URL的请求。但是在实际使用中,我们发现,如果不能知道具体执行的是哪个方法,在使用拦截器时就会犯难。例如,前阵子,我在SpringMVC 3.1.1的老版本项目中想要使用拦截器做幂等控制,发现先要针对特定请求进行拦截处理根本不可能。因为不知道是哪个方法处理的,也就无从获取方法上的注解,也就拿不到注解上的配置。因此,有必要抽象出来一个新的概念来适应这种场景。我觉得这可能是HandlerMethod诞生的背景。而尴尬的是,HandlerMethod却是在3.1版本就出现了,真是造化弄人。
言归正传,HandlerMethod,意思是Handler的方法,这个名字简直不能再清楚了,就不过多解释了。该类是对目标处理方法的封装,包括目标对象、目标方法。
实际上,如果不看源代码,你压根不会知道他,似乎是官方有意隐藏他的存在。或许因为他只是一个中间桥梁,将@RequestMapping方法与HandlerMapping、HandlerAdapter进行衔接。不管是RequestMappingHandlerMapping、还是RequestMappingHandlerAdapter都是在强调@RequestMapping,而不是HandlerMethod。虽然有点尴尬,但真是深藏功与名!
HandlerAdpater
说完了Handler,我们发现他太花里胡哨了,这DispatcherServlet要适配他,也太累了吧。别急,上设计模式——适配器。
为了适配这五种Handler,SpringMVC给他们分别设计了一个HandlerApdapter。这样DispatcherServlet就可以统一调度他们了。
public interface HandlerAdapter {
/**
* 是否可以适配handler
* 一般而言,会通过处理器的类型来判断。一个HandlerAdatper只能支持一个类型的handler
*/
boolean supports(Object handler);
/**
* 使用给定的handler处理请求。处理流程可能大不相同。
*
* @param request 当前HTTP请求
* @param response 当前HTTP响应
* @param handler 处理器. 该对象必须通过{@code supports}方法确认可以适配。
* @return 一个ModelAndView对象,包含视图名称和必要的视图数据。如果请求被直接处理完成,则返回null
* @throws Exception 任何可能发生的错误
*/
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
DispatcherServlet在处理请求时,会遍历所有的适配器,找到可以适配的HandlerAdapter并调用他的handle方法进行处理。
OK。继续,上面我们说了是分别设计一个HandlerAdapter进行适配,也就意味着,HandlerAdapter与Handler是一一对应的。
处理器 | 处理器适配器 | 备注 |
---|---|---|
@Controller的@RequestMapping | RequestMappingHandlerAdapter | 实际上该适配并不是直接适配@RequestMapping的,中间的桥梁是HandlerMethod |
Controller接口 | SimpleControllerHandlerAdapter | |
HttpRequestHandler接口 | HttpRequestHandlerAdapter | |
Servlet | SimpleServletHandlerAdapter | |
HandlerFunction | SimpleServletHandlerAdapter | SpringMVC 5.2之后提供的FunctionalInterface接口 |
小结
- SpringMVC通过适配器模式,对Handler进行适配,对上层组件隐藏了实际调用逻辑。
- Handler与HandlerAdapter是一一对应的。
- HandlerMethod是@RequestMapping与RequestMappingHandlerAdapter的桥梁。RequestMappingHandlerAdapter实际上是对HandlerMethod的适配。
后记
搞清楚HandlerAdapter的作用之后,我们下面重点关注最常用,也是最重要的RequestMappingHandlerAdapter是怎么实现的。
上一篇:
探索SpringMVC-九大组件
下一篇:
探索SpringMVC-HandlerAdapter之RequestMappingHandlerAdapter-参数解析
第一篇:
探索SpringMVC-web上下文