Spring MVC 源码分析之 AbstractHandlerMethodAdapter#handle 方法

前言:

前面的篇章我们分析了 Spring MVC 工作流程中的 HandlerMapping、HandlerAdapter 的适配过程,以及拦截器的工作流程,本篇我们来分析正真处理业务请求的过程,也就是 ha.handle(processedRequest, response, mappedHandler.getHandler()),其调用的是 AbstractHandlerMethodAdapter#handle 方法。

Spring MVC 知识传送门:

详解 Spring MVC(Spring MVC 简介)

Spring MVC 初始化源码分析

Spring MVC 工作流程源码分析

Spring MVC 源码分析之 DispatcherServlet#getHandler 方法

Spring MVC 源码分析之 DispatcherServlet#getHandlerAdapter 方法

AbstractHandlerMethodAdapter#handle 方法源码分析

AbstractHandlerMethodAdapter#handle 方法本身没有什么逻辑,内部调用了 RequestMappingHandlerAdapter#handleInternal 方法,该方法会对 Request 请求做一些判断,最终调用 RequestMappingHandlerAdapter#invokeHandlerMethod 方法去处理请求。

//org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
	return this.handleInternal(request, response, (HandlerMethod)handler);
}


//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
	//检查请求 主要检查是否是支持的请求 或者 requireSession 不为空 获取不到 session 校验不通过就抛出异常
	this.checkRequest(request);
	//ModelAndView
	ModelAndView mav;
	//是否是同步会话
	if (this.synchronizeOnSession) {
		//获取session
		HttpSession session = request.getSession(false);
		//session 为空判断
		if (session != null) {
			//本质就是获取 session 
			Object mutex = WebUtils.getSessionMutex(session);
			//加锁
			synchronized(mutex) {
				//处理业务方法 也就是 handler 执行请求处理
				mav = this.invokeHandlerMethod(request, response, handlerMethod);
			}
		} else {
			//没有可用的 session 无需互斥
			//处理业务方法 也就是 handler 执行请求处理
			mav = this.invokeHandlerMethod(request, response, handlerMethod);
		}
	} else {
		//无需同步会话
		//处理业务方法 也就是 handler 执行请求处理
		mav = this.invokeHandlerMethod(request, response, handlerMethod);
	}
	//判断响应是否需要设置缓存  指定时间内可以直接使用缓存
	if (!response.containsHeader("Cache-Control")) {
		if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
			this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
		} else {
			this.prepareResponse(response);
		}
	}

	return mav;
}

RequestMappingHandlerAdapter#invokeHandlerMethod 方法源码分析

RequestMappingHandlerAdapter#invokeHandlerMethod 会创建一个 ServletInvocableHandlerMethod 实例,并给它设置各个组件,并,会创建模型视图容器 ModelAndViewContainer,用于封装视图、数据模型等,同时会对异步请求做一些处理,通过调用ServletInvocableHandlerMethod#invokeAndHandle 方法执行业务,返回 ModelAndView。

//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
	//将请求响应封装成 ServletWebRequest
	ServletWebRequest webRequest = new ServletWebRequest(request, response);

	ModelAndView var15;
	try {
		//把所有使用 @InitBinder 注解修饰的方法 包装成 WebDataBinderFactory 对象
		WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
		//把所有使用 @ModelAttribute 注解修饰的方法 包装成 ModelFactory 对象
		ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
		//将 handlerMethod 包装成 ServletInvocableHandlerMethod 对象
		ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod);
		//设置参数解析器
		if (this.argumentResolvers != null) {
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
		}
		//设置返回值处理组件
		if (this.returnValueHandlers != null) {
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
		}
		//设置 binderFactory
		invocableMethod.setDataBinderFactory(binderFactory);
		//设置 parameterNameDiscoverer
		invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
		//创建模型视图容器对象
		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		//添加重定向相关的参数 flashMap 对象 重定向参数保存在 flashMap 中
		mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
		//将 @ModelAttribute 注解修饰的方法将对应的属性存放到 mavContainer 的 model 中
		modelFactory.initModel(webRequest, mavContainer, invocableMethod);
		//重定向时忽略默认模型 ignoreDefaultModelOnRedirect 默认值 false
		mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
		//处理异步调用 创建一个 AsyncWebRequest
		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);
		Object result;
		//异步请求的处理
		if (asyncManager.hasConcurrentResult()) {
			result = asyncManager.getConcurrentResult();
			mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
			asyncManager.clearConcurrentResult();
			LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
				String formatted = LogFormatUtils.formatValue(result, !traceOn);
				return "Resume with async result [" + formatted + "]";
			});
			invocableMethod = invocableMethod.wrapConcurrentResult(result);
		}
		//调用具体的业务方法
		invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
		//异步请求处理是否开始
		if (asyncManager.isConcurrentHandlingStarted()) {
			result = null;
			return (ModelAndView)result;
		}
		//获取 ModelAndView 对象
		var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
	} finally {
		//请求完成后的一些处理 会将 requestActive 设置为 false 也就是未激活
		webRequest.requestCompleted();
	}
	//返回
	return var15;
}

RequestMappingHandlerAdapter#getDataBinderFactory 方法源码分析

RequestMappingHandlerAdapter#getDataBinderFactory 方法主要作用是根据 handlerMethod 创建一个 WebDataBinderFactory 对象 。

//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getDataBinderFactory
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
	//获取 handlerMethod 的 type 
	Class<?> handlerType = handlerMethod.getBeanType();
	//从缓存中获取对应的 InitBinder 方法
	Set<Method> methods = (Set)this.initBinderCache.get(handlerType);
	//为空判断
	if (methods == null) {
		//缓存中没有获取到 去 handlerType 去类中查找所有标注了 @InitBinder 注解的方法 并将其缓存
		methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
		this.initBinderCache.put(handlerType, methods);
	}
	//InvocableHandlerMethod 对象集合
	List<InvocableHandlerMethod> initBinderMethods = new ArrayList();
	//从标注了 @ControllerAdvice 注解的类中寻找 @InitBinder 注解修饰的方法 并为其创建 InvocableHandlerMethod 对象
	this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
		if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
			Object bean = controllerAdviceBean.resolveBean();
			Iterator var6 = methodSet.iterator();

			while(var6.hasNext()) {
				Method method = (Method)var6.next();
				//为 method 创建 InvocableHandlerMethod 对象  并加入 initBinderMethods 中
				initBinderMethods.add(this.createInitBinderMethod(bean, method));
			}
		}

	});
	Iterator var5 = methods.iterator();

	while(var5.hasNext()) {
		Method method = (Method)var5.next();
		Object bean = handlerMethod.getBean();
		//为 method 创建 InvocableHandlerMethod 对象  并加入 initBinderMethods 中
		initBinderMethods.add(this.createInitBinderMethod(bean, method));
	}
	//使用 InvocableHandlerMethod 集合 创建 WebDataBinderFactory 对象
	return this.createDataBinderFactory(initBinderMethods);
}

RequestMappingHandlerAdapter#getModelFactory 方法源码分析

RequestMappingHandlerAdapter#getModelFactory方法主要作用是根据 @SessionAttributes 注解和 @ModelAttribute 注解修饰的方法以及 binderFactory 创建一个 ModelFactory 对象 。

//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getModelFactory
private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
	//处理 @SessionAttributes 注解
	SessionAttributesHandler sessionAttrHandler = this.getSessionAttributesHandler(handlerMethod);
	//获取 handlerMethod 的 type 
	Class<?> handlerType = handlerMethod.getBeanType();
	//用缓存中获取
	Set<Method> methods = (Set)this.modelAttributeCache.get(handlerType);
	if (methods == null) {
		//缓存为空  去 handlerType 类中寻找所有被 @ModelAttribute  注解修饰的方法
		methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
		//加入缓存
		this.modelAttributeCache.put(handlerType, methods);
	}
	
	//InvocableHandlerMethod 集合
	List<InvocableHandlerMethod> attrMethods = new ArrayList();
	从标注了 @ControllerAdvice 注解的类中寻找 @ModelAttribute 注解修饰的方法 并为其创建 InvocableHandlerMethod 对象
	this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
		if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
			Object bean = controllerAdviceBean.resolveBean();
			Iterator var7 = methodSet.iterator();

			while(var7.hasNext()) {
				Method method = (Method)var7.next();
				//为 method 创建 InvocableHandlerMethod 对象  并加入 initBinderMethods 中
				attrMethods.add(this.createModelAttributeMethod(binderFactory, bean, method));
			}
		}

	});
	Iterator var7 = methods.iterator();

	while(var7.hasNext()) {
		Method method = (Method)var7.next();
		Object bean = handlerMethod.getBean();
		//为 method 创建 InvocableHandlerMethod 对象  并加入 initBinderMethods 中
		attrMethods.add(this.createModelAttributeMethod(binderFactory, bean, method));
	}
	//根据 attrMethods binderFactory sessionAttrHandler 创建 ModelFactory
	return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}

ModelFactory#initModel 方法源码分析

ModelFactory#initModel 方法主要作用是把 @SessionAttributes 注解和 @ModelAttribute 注解修饰方法的参数初始化到容器中。

//org.springframework.web.method.annotation.ModelFactory#initModel
public void initModel(NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod) throws Exception {
	//解析 @SessionAttributes 注解 的参数
	Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
	//合并 @SessionAttributes 注解修饰方法的参数
	container.mergeAttributes(sessionAttributes);
	//调用被 @ModelAttribute 注解修饰的方法
	this.invokeModelAttributeMethods(request, container);
	//查找 @SessionAttributes  注解修饰方法的参数
	Iterator var5 = this.findSessionAttributeArguments(handlerMethod).iterator();

	while(var5.hasNext()) {
		String name = (String)var5.next();
		if (!container.containsAttribute(name)) {
			//解析参数
			Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
			if (value == null) {
				throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
			}
			//加入到 模型视图容器中
			container.addAttribute(name, value);
		}
	}

}

ServletInvocableHandlerMethod#invokeAndHandle 方法源码分析

ServletInvocableHandlerMethod#invokeAndHandle 方法主要是调用了具体的业务方法,然后对返回值进行判断处理,封装返回值到 ModelAndViewContainer 中。

//org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
	//调用 controller 中的具体方法
	Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
	//设置响应状态码
	this.setResponseStatus(webRequest);
	//返回值判断
	if (returnValue == null) {
		//
		if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {
			//是否禁用缓存
			this.disableContentCachingIfNecessary(webRequest);
			//设置请求已经处理
			mavContainer.setRequestHandled(true);
			return;
		}
	} else if (StringUtils.hasText(this.getResponseStatusReason())) {
		//请求有错误原因 设置请求已经处理
		mavContainer.setRequestHandled(true);
		return;
	}
	//请求有返回值 且没有错误原因 设置请求未处理  继续处理请求 
	mavContainer.setRequestHandled(false);
	//断言 returnValueHandlers
	Assert.state(this.returnValueHandlers != null, "No return value handlers");

	try {
		//选择合适的 HandlerMethodReturnValueHandler 处理返回值
		this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
	} catch (Exception var6) {
		if (this.logger.isTraceEnabled()) {
			this.logger.trace(this.formatErrorForReturnValue(returnValue), var6);
		}

		throw var6;
	}
}

InvocableHandlerMethod#invokeForRequest方法源码分析

InvocableHandlerMethod#invokeForRequest 方法仅仅是解析了方法的参数值,然后调用了 InvocableHandlerMethod#doInvoke 方法,该方法通过桥接方法调用了具体的方法,也就是 Controller 中定义的方法。

//org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
	//获取方法参数值
	Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
	if (this.logger.isTraceEnabled()) {
		this.logger.trace("Arguments: " + Arrays.toString(args));
	}
	//调用方法
	return this.doInvoke(args);
}


//org.springframework.web.method.support.InvocableHandlerMethod#doInvoke
@Nullable
protected Object doInvoke(Object... args) throws Exception {
	//底层就是 setAccessible(true)  也就是禁止 java 语言访问检查 如果 false 就是强制 java 语言访问检查
	ReflectionUtils.makeAccessible(this.getBridgedMethod());

	try {
		//获取桥接方法实例 并执行实际方法  其实就是 controller 类中的方法
		return this.getBridgedMethod().invoke(this.getBean(), args);
	} catch (IllegalArgumentException var4) {
		this.assertTargetBean(this.getBridgedMethod(), this.getBean(), args);
		String text = var4.getMessage() != null ? var4.getMessage() : "Illegal argument";
		throw new IllegalStateException(this.formatInvokeError(text, args), var4);
	} catch (InvocationTargetException var5) {
		Throwable targetException = var5.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(this.formatInvokeError("Invocation failure", args), targetException);
		}
	}
}

桥接方法:通过判断方法名、参数的个数以及泛型类型参数来获取桥接方法的实际方法(希望后续有时间去研究一下桥接方法)。

RequestMappingHandlerAdapter#getModelAndView 方法源码分析

RequestMappingHandlerAdapter#getModelAndView 主要是从 ModelAndViewContainer 中取出结果,包装成 ModelAndView 并返回给前端控制器 DispatcherServlet,至此整个 Handler 处理器的调用完成,后续进入视图处理阶段。

//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getModelAndView
@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
	//更新 ModelAndViewContainer 中的 model 属性
	modelFactory.updateModel(webRequest, mavContainer);
	//请求已经处理 返回 null
	if (mavContainer.isRequestHandled()) {
		return null;
	} else {
		//从模型视图容器中取出 model
		ModelMap model = mavContainer.getModel();
		//创建 模型视图
		ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
		if (!mavContainer.isViewReference()) {
			//设置模型视图的 视图
			mav.setView((View)mavContainer.getView());
		}
		//初始 重定向 的参数
		if (model instanceof RedirectAttributes) {
			Map<String, ?> flashAttributes = ((RedirectAttributes)model).getFlashAttributes();
			HttpServletRequest request = (HttpServletRequest)webRequest.getNativeRequest(HttpServletRequest.class);
			if (request != null) {
				RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
			}
		}
		//返回
		return mav;
	}
}

至此 AbstractHandlerMethodAdapter#handle 方法的调用链路源码分析完毕,这部分也是 Spring MVC 真正调用 Controller 中定义方法的一段源码,希望可以帮助到有需要的小伙伴们。

欢迎提出建议及对错误的地方指出纠正。

  • 39
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值