SpringBoot一个请求的处理全过程分享
作者:骑个小蜗牛
平时只是在用SpringBoot框架,但并没有详细研究过请求执行的一个具体过程,所以本文主要来梳理一下SpringBoot请求处理的全过程。
请求处理流程图
容器包含关系图
请求简要流程图
请求详细流程图
请求处理流程详解
请求处理主要流程
- 过滤器链chain.doFilter之前的执行(过滤器是在Server容器中的,如Tomcat);
- 拦截器链preHandle方法执行;
- 路径映射、参数绑定(参数解析、参数转换、参数校验);
- Controller的具体方法执行;
- 返回值处理(含信息转换);
- 拦截器链postHandle方法执行;
- 异常解析器处理异常(@ControllerAdvice、自定义异常解析器都在这里执行);
- 视图解析渲染;
- 拦截器链afterCompletion方法执行;
- 过滤器链chain.doFilter之后的执行。
请求处理详细流程
Tomcat线程接受到请求,经过一系列调用后,调用到ApplicationFilterChain的doFilter方法。doFilter方法调用ApplicationFilterChain的internalDoFilter方法,依次执行过滤器链的每个Filter的doFilter。
过滤器链的所有doFIlter执行完毕, 控制权交回ApplicationFilterChain, 经过一系列调用后,调用到DispatcherServlet的doDispatch方法。
doDispatch方法的主要流程:
- DispatcherServlet的getHandler方法:得到处理执行器链(包含处理器和拦截器链)。
- DispatcherServlet的getHandlerAdapter方法:得到处理器适配器。
- HandlerExecutionChain的applyPreHandle方法:执行执行器链中的所有拦截器方法preHandle。
AbstractHandlerMethodAdapter的handle方法:该方法主要包含路径映射、参数bangd (参数解析、参数转换、参数校验)、调用具体控制器方法、返回值处理(含信息转换)等操作。
handle方法的主要流程:
- 调用RequestMappingHandlerAdapter的handleInternal方法
- handleInternal方法又调用RequestMappingHandlerAdapter的invokeHandlerMethod方法
invokeHandlerMethod方法的主要流程:
- 调用RequestMappingHandlerAdapter的createInvocableHandlerMethod方法:注册参数解析器、返回值处理器、信息转化器等到ServletInvocableHandlerMethod 对象实例中。
- 调用ServletInvocableHandlerMethod的invokeAndHandle方法。
invokeAndHandle方法的主要流程:
- 调用InvocableHandlerMethod的invokeForRequest方法
- invokeForRequest方法又调用InvocableHandlerMethod的doInvoke方法
doInvoke方法的主要流程:
- 调用InvocableHandlerMethod的getMethodArgumentValues方法:路径映射、参数绑定(参数解析、参数转换、参数校验)。
- 调用Method的invoke方法,内部调用DelegatingMethodAccessorImpl的invoke方法,内部调用InvocableHandlerMethod的doInvoke方法,内部调用NativeMethodAccessorImpl的invoke方法,内部调用NativeMethodAccessorImpl的invoke0方法,内部调用具体Controller的具体方法,得到响应结果。
- 调用HandlerMethodReturnValueHandlerComposite的handleReturnValue方法:返回值处理(含信息转换)。
- 调用HandlerExecutionChain的applyPostHandle方法:执行执行器链中的所有拦截方法postHandle。
- 调用DispatcherServlet的processDispatchResult方法。
processDispatchResult方法的主要流程:
- 调用DispatcherServlet的processHandlerException方法:异常处理(获取合适的异常解析器处理异常信息,@ControllerAdvice全局异常处理和自定义异常解析器都是在这一步执行的)。
- 调用DispatcherServlet的render方法:视图解析渲染。
- 调用HandlerExecutionChain的triggerAfterCompletion方法:执行执行器链中的所有拦截方法afterCompletion。
- 控制权交回ApplicationFilterChain , 继续执行过滤器链的所有doFIlter之后的代码。
常见问题
全局异常处理失效
1.@ControllerAdvice作用范围
拦截器的preHandle方法、postHandle方法抛出的异常在ControllerAdvice处理范围内,但拦截器的afterCompletion方法抛出的异常不在处理范围内(拦截器的afterCompletion抛出的异常会被直接catch处理,不会往外抛出异常,只会打印错误日志)。
HandlerExecutionChain类源码
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = this.interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; try { interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable ex2) { logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } } }
过滤器抛出的异常不在ControllerAdvice处理范围内。要处理过滤器抛出的异常,可以自定义Filter并放在过滤链的最前面,catch处理异常。
2.多个@ControllerAdvice优先级问题
- 多个使用@ControllerAdvice 的Bean按执行顺序(通过Order注解设置执行顺序,值越小月优先执行)依次执行
- 当某个Bean的方法匹配上异常时,进行异常处理,直接返回,后续的方法和Bean不在执行。
关于全局异常处理详细讲解可参考文章:[SpringBoot全局异常处理]
后续文章会继续针对请求流程里面的一些主要功能作深入探讨,如:过滤器、拦截器、参数解析、参数转换、参数校验、返回值处理、异常处理等方面。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。