HandlerAdapter介绍
在前面的SpringMVC中的HandlerMapping一文中已经说到,对于一个请求,SpringMVC中的DispatcherServlet
会通过特定的HandlerMapping
得到HandlerExecutionChain
,HandlerExecutionChain
对象中持有一个 handler 成员变量。
此后,DispatcherServlet
会遍历注册在IOC容器中的HandlerAdapter
实例,看哪一种HandlerAdapter
是支持这个 handler 的,如果找到了那么该HandlerAdapter
会调用自己的handle()
方法,运用java的反射机制执行 handler 的具体方法来获得ModelAndView
,也就是前端要展示的页面和数据。
因为前面说过这个 handler 会有可能是不同的类型,所以需要对不同类型做适配,所以才有了HandlerAdapter
(处理器适配器)的概念。
HandlerAdapter
接口:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/**
* MVC framework SPI interface, allowing parameterization of core MVC workflow.
*
* <p>Interface that must be implemented for each handler type to handle a request.
* This interface is used to allow the {@link DispatcherServlet} to be indefinitely
* extensible. The DispatcherServlet accesses all installed handlers through this
* interface, meaning that it does not contain code specific to any handler type.
*
* <p>Note that a handler can be of type <code>Object</code>. This is to enable
* handlers from other frameworks to be integrated with this framework without
* custom coding, as well as to allow for annotation handler objects that do
* not obey any specific Java interface.
*
* <p>This interface is not intended for application developers. It is available
* to handlers who want to develop their own web workflow.
*
* <p>Note: HandlerAdaptger implementators may implement the
* {@link org.springframework.core.Ordered} interface to be able to specify a
* sorting order (and thus a priority) for getting applied by DispatcherServlet.
* Non-Ordered instances get treated as lowest priority.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
* @see org.springframework.web.servlet.handler.SimpleServletHandlerAdapter
*/
public interface HandlerAdapter {
/**
* Given a handler instance, return whether or not this HandlerAdapter can
* support it. Typical HandlerAdapters will base the decision on the handler
* type. HandlerAdapters will usually only support one handler type each.
* <p>A typical implementation:
* <p><code>
* return (handler instanceof MyHandler);
* </code>
* @param handler handler object to check
* @return whether or not this object can use the given handler
*/
//判断当前 HandlerAdapter 是否支持处理 handler
boolean supports(Object handler);
/**
* Use the given handler to handle this request.
* The workflow that is required may vary widely.
* @param request current HTTP request
* @param response current HTTP response
* @param handler handler to use. This object must have previously been passed
* to the <code>supports</code> method of this interface, which must have
* returned <code>true</code>.
* @throws Exception in case of errors
* @return ModelAndView object with the name of the view and the required
* model data, or <code>null</code> if the request has been handled directly
*/
//使用 handler 处理请求
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
/**
* Same contract as for HttpServlet's <code>getLastModified</code> method.
* Can simply return -1 if there's no support in the handler class.
* @param request current HTTP request
* @param handler handler to use
* @return the lastModified value for the given handler
* @see javax.servlet.http.HttpServlet#getLastModified
* @see org.springframework.web.servlet.mvc.LastModified#getLastModified
*/
long getLastModified(HttpServletRequest request, Object handler);
}
HandlerAdapter
有如下几个主要实现类。
SimpleServletHandlerAdapter
SimpleServletHandlerAdapter
可以处理类型为Servlet
的 handler,对 handler 的处理是调用Servlet
的service()
方法处理请求。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class SimpleServletHandlerAdapter implements HandlerAdapter {
public boolean supports(Object handler) {
return (handler instanceof Servlet);
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((Servlet) handler).service(request, response);
return null;
}
public long getLastModified(HttpServletRequest request, Object handler) {
return -1;
}
}
演示示例,编写一个TestServlet
继承HttpServlet
。1
2
3
4
5
6
7
8
9"/testServlet") (
public class TestServlet extends HttpServlet {
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Response from TestServlet");
}
}
此外还需要手动注入SimpleServletHandlerAdapter
实例。如果不手动注入的话,会报一个找不到adapter的异常。但是 <mvc:annotation-driven /> 会帮我们注入 RequestMappingHandlerAdapter
、HttpRequestHandlerAdapter
和 SimpleControllerHandlerAdapter
这三个适配器。
1 |
|
debug查看:
http请求的结果:
SimpleControllerHandlerAdapter
SimpleControllerHandlerAdapter
可以处理类型为Controller
的 handler,对 handler 的处理是调用Controller
的handleRequest()
方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public class SimpleControllerHandlerAdapter implements HandlerAdapter {
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
同样进行代码演示,编写一个TestController
实现Controller
接口。1
2
3
4
5
6
7
8
9
10"/testController") (
public class TestController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.getWriter().write("Response from TestController");
return null;
}
}
因为使用SpringBoot项目,此处我们也不需要手动注入适配器了,直接debug查看:
在浏览器中发送请求:
HttpRequestHandlerAdapter
HttpRequestHandlerAdapter
可以处理类型为HttpRequestHandler
的 handler,对 handler 的处理是调用HttpRequestHandler
的handleRequest()
方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public class HttpRequestHandlerAdapter implements HandlerAdapter {
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
同样的编写一个类TestHttpRequestHandler
实现HttpRequestHandler
接口。1
2
3
4
5
6
7
8
9"/testHttpRequestHandler") (
public class TestHttpRequestHandler implements HttpRequestHandler {
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().write("Response from TestHttpRequestHandler");
}
}
debug查看:
在浏览器中发送请求:
RequestMappingHandlerAdapter
RequestMappingHandlerAdapter
可以处理类型为HandlerMethod
的 handler(对应@RequestMapping
这种映射请求的方式),对 handler 的处理是调用通过java反射调用HandlerMethod
的方法,最终得到一个ModelAndView
对象。它的代码相比之前三个HandlerAdapter
要复杂很多,这里只简单介绍一下。
RequestMappingHandlerAdapter
继承了AbstractHandlerMethodAdapter
类,AbstractHandlerMethodAdapter
中几个重要方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
//省略...
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
/**
* Given a handler method, return whether or not this adapter can support it.
* @param handlerMethod the handler method to check
* @return whether or not this adapter can adapt the given method
*/
protected abstract boolean supportsInternal(HandlerMethod handlerMethod);
/**
* This implementation expects the handler to be an {@link HandlerMethod}.
*/
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
/**
* Use the given handler method to handle the request.
* @param request current HTTP request
* @param response current HTTP response
* @param handlerMethod handler method to use. This object must have previously been passed to the
* {@link #supportsInternal(HandlerMethod)} this interface, which must have returned {@code true}.
* @return a ModelAndView object with the name of the view and the required model data,
* or {@code null} if the request has been handled directly
* @throws Exception in case of errors
*/
protected abstract ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;
}
RequestMappingHandlerAdapter
的几个重写的方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
}
演示代码的话很简单,使用最常见的@RequestMapping
注解就可以了,此处不再赘述。1
2
3
4
5
6
7
8
9
10
11
12
13
public class TestRequestMapping {
"/testRequestMapping") (
public void test(HttpServletResponse response) {
try {
response.getWriter().write("Response from TestHttpRequestHandler");
} catch (IOException e) {
e.printStackTrace();
}
}
}