1、前言
在SpringMVC中,我们都知道有HandlerAdapter组件的存在,虽然在我们的日常使用中并不会感知到它的存在,不过有些人也可能遇到过如下bug:
No adapter for handler [xxx]: The DispatcherServlet configuration
needs to include a HandlerAdapter that supports this handler
今天我们就来聊聊,关于SpringMVC中HandlerAdapter组件的作用以及为什么要使用装饰者模式。
2、为什么要使用装饰者模式
SpringMVC在DispatchServlet的doDispatch方法中,对HandlerMapping接口获取到的Handler使用装饰者模式进行了处理,使其变成了HandlerAdapter类型:
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
在此之前有一点需要说一下,handler实际上就是真正处理业务逻辑的方法,比如下面的例子中,hello方法就是我们的handler:
@GetMapping("/hello")
public String hello(){
//……doSomething
}
从源码中我们可以看到,SpringMVC在getHandlerInternal方法中,得到的其实是一个object类型。
虽然getHandler方法最终给我们返回的是HandlerExecutionChain,但这只是因为封装了拦截器链,并不影响handler是object类型的实质。
但是在最终我们是需要通过反射来调用handler实现业务的调用,object类型很明显没办法实现这个效果。
如果handler有统一接口的话倒还好说,但是handler不仅没有统一接口,而且实现类还不止一个:
- Controller接口
- HttpRequestHandler 接口
- HttpServlet 接口
- @RequestMapping方法注解
当dispatchServlet获取当对应的Handler之后如何调用呢?调用其哪个方法?
这里有两种解决办法:
一是用instanceof 判断Handler 类型然后调用相关方法 。
二是通过引入适配器实现,每个适配器实现对指定Handler的调用。
SpringMVC采用的是后者。
3、HandlerAdapter简述
HandlerAdapter的实现类除去废弃和抽象之外,实现类有如下四个,分别对应上述的四个
关于SpringMVC是怎么通过HandlerAdapter来解决上面问题的,有兴趣的读者可以自己去看看源码,这里不作描述。