03 Spring MVC 源码总结 - 内置处理器 HandlerAdapter 分析

前文 02 Spring MVC 源码总结 - 内置处理器 HandlerMapping 分析
介绍了 SpringMVC 中的 handler 有多种实现方式, 实现 Controller 接口或实现 HttpRequestHandler 对象以及通过注解控制器的方式都可实现一个 handler。由于实现方式不一样,调用方式就不确定了,所以引入 HandlerAdapter。

适配器模式

适配器模式(Adapter Pattern),把一个类的接口变换成客户端所期待的另一种接口, Adapter模式使原本因接口不匹配(或者不兼容)而无法在一起工作的两个类能够在一起工作。

HandlerAdapter 类关系图

在这里插入图片描述

  • HandlerAdapter
    HandlerAdapter 作为父接口,定义了三个方法供子类实现
	/**
	 * 是否支持该处理器
	 */
	boolean supports(Object handler);

	/**
	 * 执行处理器,返回ModelAndView结果
	 */
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

	/**
	 * 返回请求的最新更新时间,如果不支持该操作,则返回-1即可
	 */
	long getLastModified(HttpServletRequest request, Object handler);
  • HttpRequestHandlerAdapter
    用于处理实现 HttpRequestHandler 接口的对象,在handler()方法中直接调用重写的handleRequest()方法即可
    在这里插入图片描述

  • SimpleControllerHandlerAdapter
    用于处理实现 Controller 接口的对象,在handler()方法中直接调用重写的handleRequest()方法即可
    在这里插入图片描述

  • RequestMappingHandlerAdapter
    用于处理实现@Controller注解,自定义方法的调用,后面具体分析

源码分析

DispatcherServlet::doDispatch() 中,取得 handler 对象后会根据 handler 匹配具体的 Adapter,然后调用重写的 handle() 方法执行业务流程
在这里插入图片描述

getHandlerAdapter()

遍历HandlerAdapter对象,调用重写的supports()方法获得当前handler对应的HandlerAdapter对象
在这里插入图片描述

handle()

这里重点介绍下基于注解实现自定义的方法的调用,也就是 RequestMappingHandlerAdapter::handle()
跟踪源码,到达关键的执行方法 invokeHandlerMethod(),核心步骤:

  1. 解决数据绑定问题 @InitBinder
  2. 获取model相关的属性 @ModelAttribute
  3. 创建 HandlerMethod 对象,具备了返回值的处理功能,并且能够处理@ResponseStatus 注解
  4. 创建ModelAndViewContainer对象,用于保存model和View对象
  5. 创建AsyncWebRequest异步请求对象
  6. 创建WebAsyncManager异步请求管理器对象
  7. 执行具体调用
  8. 处理完请求后的后置处理
    • 调用ModelFactory的updateModel方法更新model,包括设置SessionAttribute和给Model设置BinderResult
    • 根据mavContainer创建了ModelAndView
    • 如果mavContainer里的model是RedirectAttributes类型,则将其设置到FlashMap
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		// 使用request和response创建ServletWebRequest对象
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
			// 1. 解决数据绑定问题 @InitBinder
			// 创建WebDataBinderFactory对象,此对象用来创建WebDataBinder对象,进行参数绑定,
			// 实现参数跟String之间的类型转换,ArgumentResolver在进行参数解析的过程中会用到WebDataBinder
 			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
 			// 2. 获取model相关的属性 @ModelAttribute
			// 创建ModelFactory对象,此对象主要用来处理model,主要是两个功能,1是在处理器具体处理之前对model进行初始化,2是在处理完请求后对model参数进行更新
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

			// 3. 创建 HandlerMethod 对象,具备了返回值的处理功能,并且能够处理@ResponseStatus 注解
			// 创建ServletInvocableHandlerMethod对象,并设置其相关属性,实际的请求处理就是通过此对象来完成的,参数绑定、处理请求以及返回值处理都在里边完成
			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);


			// 4.创建ModelAndViewContainer对象,用于保存model和View对象
			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
			// 将flashmap(参数传递时的参数结构)中的数据设置到model中
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
			// 使用modelFactory将sessionAttributes和注释了@ModelAttribute的方法的参数设置到model中
			modelFactory.initModel(webRequest, mavContainer, invocableMethod);
			// 根据配置对ignoreDefaultModelOnRedirect进行设置
			mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

			// 5.创建AsyncWebRequest异步请求对象
			AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
			asyncWebRequest.setTimeout(this.asyncRequestTimeout);

			// 6.创建WebAsyncManager异步请求管理器对象
			WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
			asyncManager.setTaskExecutor(this.taskExecutor);
			asyncManager.setAsyncWebRequest(asyncWebRequest);
			asyncManager.registerCallableInterceptors(this.callableInterceptors);
			asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
			// 如果当前异步请求已经处理并得到结果,则将返回的结果放到mavContainer对象中,然后将invocable对象进行包装转换,转成需要的执行对象然后开始执行
			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 + "]";
				});
				// 转换具体的invocable执行对象
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}

			// 7.执行调用
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}
			// 8.处理完请求后的后置处理,此处一共做了三件事,
			// 1、调用ModelFactory的updateModel方法更新model,包括设置SessionAttribute和给Model设置BinderResult
			// 2、根据mavContainer创建了ModelAndView
			// 3、如果mavContainer里的model是RedirectAttributes类型,则将其设置到FlashMap
			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			// 标记请求完成
			webRequest.requestCompleted();
		}
	}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小刘说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值