SpringMVC 组件-HandlerAdapter

227 阅读5分钟

HandlerAdapter 在 SpringMVC 中相当于是执行 Handler 的对象。

下面是 HandlerAdapter 的类结构图。

HandlerAdapter.png

HandlerAdapter 接口

public interface HandlerAdapter {
	boolean supports(Object handler);
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
	long getLastModified(HttpServletRequest request, Object handler);
}

HandlerAdapter 接口中定义了三个方法。

  • supports 方法返回当前 HandlerAdapter 是否支持出传入的 handler。
  • handle 方法,对请求进行处理。
  • 返回上一次修改的时间。

SimpleServletHandlerAdapter

public boolean supports(Object handler) {
	return (handler instanceof Servlet);
}

SimpleServletHandlerAdapter 能执行的 handler 为实现了 Servlet 接口的类。

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {
	// 直接调用 servlet.service 执行
	((Servlet) handler).service(request, response);
	return null;
}

直接调用了 Servlet#service 方法进行处理。

public long getLastModified(HttpServletRequest request, Object handler) {
	return -1;
}

不支持缓存。

SimpleControllerHandlerAdapter

首先看下比较简单的 SimpleControllerHandlerAdapter 的实现。

public boolean supports(Object handler) {
	//  handler 是否实现了 org.springframework.web.servlet.mvc.Controller 接口
	return (handler instanceof Controller);
}

根据 SimpleControllerHandlerAdapter#supports 方法可以得知,SimpleControllerHandlerAdapter 支持实现了 Controller 接口的类作为 Handler。

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {
	// 直接调用 handler 的 handleRequest 方法
	return ((Controller) handler).handleRequest(request, response);
}

handler 则是调用了 handleRequest 方法,handleRequest 有子类重写。在实际编写 Handler 类的时候,可以通过继承 AbstractController 类,并重写 handleRequestInternal 方法来进行处理。

public long getLastModified(HttpServletRequest request, Object handler) {
	// 是否是 LastModified 类型
	if (handler instanceof LastModified) {
		// 如果是的话,则判断一下资源是否过期
		return ((LastModified) handler).getLastModified(request);
	}
	// 返回 -1 表示需要获取最新的资源
	return -1L;
}

如果 Handler 实现了 LastModified 接口,则调用处理器的 getLastModified 方法来决定是否启动缓存。

HttpRequestHandlerAdapter

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

从 HttpRequestHandlerAdapter#supports 得知,其能够处理的 Handler 需要实现 HttpRequestHandler 接口。

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {
	// 直接调用 handler 的 handleRequest 方法
	((HttpRequestHandler) handler).handleRequest(request, response);
	return null;
}

处理请求的逻辑则交由具体的实现了 HttpRequestHandler 接口的类中重写的 handleRequest 来处理。 SpringMVC 中提供了默认的实现,包括 DefaultServletHttpRequestHandler,WebSocketHttpRequestHandler,SockJsHttpRequestHandler 等。

public long getLastModified(HttpServletRequest request, Object handler) {
	if (handler instanceof LastModified) {
		return ((LastModified) handler).getLastModified(request);
	}
	return -1L;
}

同样,默认的情况下,是不进行缓存的,但是可以通过在子类中重写该方法改变其行为。

HandlerFunctionAdapter

HandlerFunctionAdapter 是 Spring 5.2 新引入的 HandlerAdapter,内部的处理方法委托给了 HandlerFunction 进行处理。

RequestMappingHandlerAdapter

RequestMappingHandlerAdapter 是最常用的 HandlerAdapter 了。 RequestMappingHandlerAdapter 继承自 AbstractHandlerMethodAdapter ,并且实现了 BeanFactoryAware 以及 InitializingBean 接口。因此,RequestMappingHandlerAdapter 具备了获取 BeanFactory 以及在 Bean 初始化的时候进行额外扩展的能力。 AbstractHandlerMethodAdapter 实现了 HandlerAdapter 接口。在内部实现了接口中定义的三个方法,但同时又调用了内部定义的模板方法。模板方法在子类 RequestMappingHandlerAdapter 中实现了。并且主要的逻辑也是在子类 RequestMappingHandlerAdapter 中。

还是先看一下 HandlerAdapter 中定义的三个接口方法。

protected boolean supportsInternal(HandlerMethod handlerMethod) {
	// 直接返回 true,也就是只要满足 handler 是 HandlerMethod 类型即可
	return true;
}

可以看到直接返回了 true,也就是说主需要看 AbstractHandlerMethodAdapter#supports 方法即可。

public final boolean supports(Object handler) {
	// handler 必须是 HandlerMethod 类型
	return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

AbstractHandlerMethodAdapter#supports 的方法只需要求 handler 是 HandlerMethod 类型即可。

继续看 AbstractHandlerMethodAdapter#getLastModified 方法,其实该方法直接调用了 RequestMappingHandlerAdapter#getLastModifiedInternal 方法。

protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
	return -1;
}

默认直接返回了 -1,不支持缓存。 最后来看最重要的 handleInternal 方法。

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) {
		// 获取当前请求中携带的 session
		HttpSession session = request.getSession(false);
		if (session != null) {
			// 获取 session mutex
			Object mutex = WebUtils.getSessionMutex(session);
			synchronized (mutex) {
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No HttpSession available -> no mutex necessary
			// 没有携带 session,那么也不需要加锁
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}
	}
	else {
		// No synchronization on session demanded at all...
		// 完全不需要加锁
		mav = invokeHandlerMethod(request, response, handlerMethod);
	}
	// 如果 response 不包含 header Cache-Control
	if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
		if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
			applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
		}
		else {
			prepareResponse(response);
		}
	}
	return mav;
}
  1. 首先第一步先去检查 request 了,因为定义了支持的请求方法,所以先要判断该请求的请求方法是否是被允许的。
  2. 后续其实的主要逻辑是到了 RequestMappingHandlerAdapter#invokeHandlerMethod 中了。
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
	// 将请求封装成 ServletWebRequest
	ServletWebRequest webRequest = new ServletWebRequest(request, response);
	try {
		// factory,用于创建 WebDataBinder
		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
		// 用于处理 model
		// 在处理器处理之前对 Model 进行初始化,在处理之后更新 Model 中的参数
		ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
		// 实际请求的处理就是经过 ServletInvocableHandlerMethod 执行的
		ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
		// 设置 argumentResolvers 属性
		if (this.argumentResolvers != null) {
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
		}
		// 设置 returnValueHandlers 属性
		if (this.returnValueHandlers != null) {
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
		}
		invocableMethod.setDataBinderFactory(binderFactory);
		invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
		// 创建 ModelAndViewContainer container
		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		// 将 flashMap 中的数据设置到 mavContainer 中
		mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
		// 将 @ModelAttributr 属性设置进去
		modelFactory.initModel(webRequest, mavContainer, invocableMethod);
		// 设置 IgnoreDefaultModelOnRedirect
		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();
	}
}
  1. 首先将 HttpServletRequest 封装成了 ServletWebRequest。
  2. 调用 RequestMappingHandlerAdapter#getDataBinderFactory 方法,找出所有的 @InitBinder 注解的方法,并封装进 WebDataBinderFactory 中。
  3. 调用 RequestMappingHandlerAdapter#getModelFactory 方法,找出所有的 @ModelAttribute 注解的方法,并封装进 ModelFactory 中。
  4. 将 HandlerMethod 封装成 ServletInvocableHandlerMethod,并设置 invocableMethod 的属性,包括 HandlerMethodReturnValueHandlerComposite 以及 HandlerMethodArgumentResolverComposite。同时还需设置其 WebDataBinderFactory,ParameterNameDiscoverer。
  5. 初始化一个 ModelAndViewContainer 容器,如果有通过 flashMap 传过来的属性,则设置到 ModelAndViewContainer 中。
  6. 调用 ModelFactory#initModel 方法,在该方法中会去执行所有标注了 @ModelAttribute 注解的方法。同时也会根据定义的 @InitBinder 方法去进行相应的处理。
  7. 后面是异步请求的处理,本文先不展开介绍。
  8. 调用 ServletInvocableHandlerMethod#invokeAndHandle 方法,这里会真正执行到我们的定义的 handlerMethod。

后记

这篇文章其实写的比较简单,更多的细节有待深挖。后续应该会写更多的深入细节的文章。

推荐阅读