SpringMVC中的HandlerAdapter

HandlerAdapter介绍

在前面的SpringMVC中的HandlerMapping一文中已经说到,对于一个请求,SpringMVC中的DispatcherServlet会通过特定的HandlerMapping得到HandlerExecutionChainHandlerExecutionChain对象中持有一个 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 的处理是调用Servletservice()方法处理请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;
}

}

演示示例,编写一个TestServlet继承HttpServlet

1
2
3
4
5
6
7
8
9
@Controller("/testServlet")
public class TestServlet extends HttpServlet {

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Response from TestServlet");
}

}

此外还需要手动注入SimpleServletHandlerAdapter实例。如果不手动注入的话,会报一个找不到adapter的异常。但是 <mvc:annotation-driven /> 会帮我们注入 RequestMappingHandlerAdapterHttpRequestHandlerAdapterSimpleControllerHandlerAdapter 这三个适配器。

1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootApplication
public class BootStrap {

public static void main(String[] args) {
SpringApplication.run(BootStrap.class, args);
}

@Bean
public SimpleServletHandlerAdapter simpleServletHandlerAdapter() {
return new SimpleServletHandlerAdapter();
}
}

debug查看:

http请求的结果:

SimpleControllerHandlerAdapter

SimpleControllerHandlerAdapter可以处理类型为Controller的 handler,对 handler 的处理是调用ControllerhandleRequest()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class SimpleControllerHandlerAdapter implements HandlerAdapter {

@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}

@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {

return ((Controller) handler).handleRequest(request, response);
}

@Override
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
@Component("/testController")
public class TestController implements Controller {

@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.getWriter().write("Response from TestController");
return null;
}

}

因为使用SpringBoot项目,此处我们也不需要手动注入适配器了,直接debug查看:

在浏览器中发送请求:

HttpRequestHandlerAdapter

HttpRequestHandlerAdapter可以处理类型为HttpRequestHandler的 handler,对 handler 的处理是调用HttpRequestHandlerhandleRequest()方法。

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
public class HttpRequestHandlerAdapter implements HandlerAdapter {

@Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}

@Override
@Nullable
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;
}

}

同样的编写一个类TestHttpRequestHandler实现HttpRequestHandler接口。

1
2
3
4
5
6
7
8
9
@Controller("/testHttpRequestHandler")
public class TestHttpRequestHandler implements HttpRequestHandler {

@Override
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
42
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {


//省略...

@Override
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}.
*/
@Override
@Nullable
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
*/
@Nullable
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
46
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {

@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}

@Override
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
@Controller
public class TestRequestMapping {

@RequestMapping("/testRequestMapping")
public void test(HttpServletResponse response) {
try {
response.getWriter().write("Response from TestHttpRequestHandler");
} catch (IOException e) {
e.printStackTrace();
}

}
}

------ 本文完 ------