在上一篇水文中,我们在了解适配器Adapter的时候停了下来,思考我们的疑问。
我们了解到适配器HandlerAdapter是在一个for循环中寻找合适的Adapter在一个集合中。
那么,看下HandlerAdapter这个接口;
public interface HandlerAdapter {
boolean supports(Object handler);
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
}
再看下实现它的,
通过上面的图片,我们是否感觉到什么?---------接口,集合。。。
是不是有点类似策略模式:针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。
那么我们分析下它定义的几个具体的算法吧。
在上面的代码中,我们仔细看的话,就会发现handle方法返回ModelAndView,这就说明它就是真正处理请求的方法。
那么我们就着重了解分析它。
在图片里,其实也就四个重要的实现类;-------把MyDummyAdapter、MyHandlerAdapter去掉。
其中三个是比较简单的,
SimpleControllerHandlerAdapter类
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
SimpleServletHandlerAdapter类,
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((Servlet) handler).service(request, response);
return null;
}
HttpRequestHandlerAdapter类,
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
通过上面,我们了解到它们分别适配不同Controller、Servlet和HttpRequestHandler的类型。但是它们非常简单,都是调用Handler里固定的方法,所以我们接下来看下RequestMappingHandlerAdapter。
虽然现在仅剩下一个RequestMappingHandlerAdapter了,但它不似前面三个那样有固定的类型。因为它处理的Handler方法可以是任意的方法,没有约束。虽然调用它不难,可以使用反射来,但是难就难在参数值的解析。参数可能有有各种各样的类型,而且有几个可能还是不确定的。
AbstractHandlerMethodAdapter接口
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
接口
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
那么它在这里是如何实现的呢?
通过继承父类的handle,实现自己的handleInternal方法。
@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;
}
好了,我们来分析这段代码。这段代码细看它就干了那么三件事。
第一个使用checkRequest,
protected final void checkRequest(HttpServletRequest request) throws ServletException {
// Check whether we should support the request method.
String method = request.getMethod();
if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods);
}
// Check whether a session is required.
if (this.requireSession && request.getSession(false) == null) {
throw new HttpSessionRequiredException("Pre-existing session required but none found");
}
}
这个方法的话,它也就干了那么两件事:
- 根据spportedMethods属性对request的类型是否支持进行判断。
- 判断requireSession是否为true,通过的话,就request.getSession(false)检查session是否存在,不存在就抛出异常。
第二个的话,就是invokeHandlerMethod方法。
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
这个方法大概实现的功能是具体执行请求处理。而且有两种运行方式,一种是synchronizeOnSession属性设置为true,则对session同步,否则不同步。
由于这里使用了类似责任链模式的方式,所以就不展开介绍。
第三个的话,就是给response设置缓存过期时间。
好了到这里,我们就讲完了大概实现适配器Adapter的程序,应该大概都知道了,它的设计是基于-----接口的适配器模式。
注:适配器模式是将某个类的接口转换成客户端期望的另一个接口表示的。
如果那里不对希望多多指教,不胜感激。
参考资料:
看透springmvc源代码分析与实践 第13章 HandlerAdapter