Spring-21 SpringMVC 处理器适配
Spring 源码系列文章会遵循由浅入深,由易到难,由宏观到微观的原则,目标是尽量降低学习难度,而不是一上来就迷失在源码当中. 文章会从一个场景作为出发点,针对性的目的性极强的针对该场景对 Spring 的实现原理,源码进行探究学习。该系列文章会让你收获什么? 从对 Spring 的使用者成为 Spring 专家。该文章会同步在微信公众号 【DevXTalk】, 方便在微信客户端阅读。
开门见山的说一些读者可能会想过, 我的发(What F*ck)我就只想发起一个请求,处理这个请求就完事了,框架给我搞的那么复杂干嘛?难道框架作者都是吃饱了撑的是吧!记住人家写的代码是面向全世界范围的广大群体,要考虑到对各种使用场景的支持。所以代码就必须灵活,要非常方便扩展,要不然有人敢用么?
这篇内容重点探讨 Spring MVC
中的 HandlerAdapter
处理器适配器.重点不在于对它的实现源码研究的多深入细致,而是培养设计思维和架构思维。
HandlerAdapter 接口定义
首先我们需要明确的是 HandlerAdapter
处理器适配器它服务的目标是 处理器
, 它是为了适配不同的处理器而存在的。因为框架需要能够灵活的扩展,处理器的形式是不固定的,可能会有很多种处理器,所以在调用处理器进行处理请求的位置代码不能被写死(不经过修改就不能改变程序的行为)。
HandlerAdapter
两个核心 API supports
判断当前适配器支不支持传入的 Handler
处理器。handle
处理请求,handle
方法的第三个参数是 Object handler 这个 handler 才是真正处理请求的。这里 handler 的参数类型是 Object
可以接收任意类型的对象非常的灵活,当然灵活带来的一个弊端就是风险, 势必要在编程时遵守某些规范。
public interface HandlerAdapter {
boolean supports(Object handler);
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
适配
首先要理解什么是适配,适配就是在两个已经存在的事物中间起到衔接作用,目的是让这两个事物可以协同工作。所以适配器一定是个中间组件,比如手机充电器的转接头,一端连着充电器,另一端连着手机。再比如一个内向的人在一个外向型的团体中,为了融入团体,他会刻意表现的偏外向一些,也可以把适配理解成一种伪装吧。
在 Spring MVC
中 HandlerAdapter
处理器适配器连接的两端是 DispatcherServlet
和 处理器。DispatcherServlet
是不知道处理器具体是什么类型,如何工作的, 它只需要和 HandlerAdapter
交互即可。
下图是 Spring MVC
中 HandlerAdapter
的结构。DispatcherServlet
和 HandlerAdapter
之间遵循着一套接口规范,处理器是各式各样的。当把这些不同的处理器伪装成 HandlerAdapter
之后,它们就可以和 DispatcherServlet
协同工作了。
内置适配器
介绍一些 Spring MVC
中已经内置的适配器。
HttpRequestHandlerAdapter
支持的处理器是 HttpRequestHandler
.
@FunctionalInterface
public interface HttpRequestHandler {
/**
* Process the given request, generating a response.
* @param request current HTTP request
* @param response current HTTP response
* @throws ServletException in case of general errors
* @throws IOException in case of I/O errors
*/
void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
}
SimpleControllerHandlerAdapter
支持的处理器是 Controller
.
@FunctionalInterface
public interface Controller {
/**
* Process the request and return a ModelAndView object which the DispatcherServlet
* will render. A {@code null} return value is not an error: it indicates that
* this object completed request processing itself and that there is therefore no
* ModelAndView to render.
* @param request current HTTP request
* @param response current HTTP response
* @return a ModelAndView to render, or {@code null} if handled directly
* @throws Exception in case of errors
*/
@Nullable
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
SimpleServletHandlerAdapter
支持的处理器是 Servlet
.
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
HandlerFunctionAdapter
支持的处理器是 HandlerFunction
.
@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;
}
开发中最常用的 RequestMappingHandlerAdapter
支持的处理器是 HandlerMethod
.
@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;
}
调用处理器的位置 org.springframework.web.method.support.InvocableHandlerMethod#doInvoke
通过反射的方式调用了处理器方法
@Nullable
protected Object doInvoke(Object... args) throws Exception {
Method method = getBridgedMethod();
try {
if (KotlinDetector.isSuspendingFunction(method)) {
return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args);
}
return method.invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(method, getBean(), args);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(formatInvokeError(text, args), ex);
}
catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else if (targetException instanceof Error) {
throw (Error) targetException;
}
else if (targetException instanceof Exception) {
throw (Exception) targetException;
}
else {
throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
}
}
}
DevX
会持续分享有趣的技术和见闻,如果你觉得本文对你有帮助希望你可以分享给更多的朋友看到。该文章会同步在微信公众号 【DevXTalk】, 方便在微信客户端阅读。