前言:
前面的篇章我们分析了 Spring MVC 工作流程中的 HandlerMapping、HandlerAdapter 的适配过程,以及拦截器的工作流程,本篇我们来分析正真处理业务请求的过程,也就是 ha.handle(processedRequest, response, mappedHandler.getHandler()),其调用的是 AbstractHandlerMethodAdapter#handle 方法。
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 中定义方法的一段源码,希望可以帮助到有需要的小伙伴们。
欢迎提出建议及对错误的地方指出纠正。