1.前置知识
- 本文是针对springMVC请求执行流程来分析,并不会设计到如何使用
- SpringMVC大体执行流程图,网上很多图,从执行大局看基本上是一致,本文是基于大图分析每一步是如何执行,处理什么来进行分析。
下图来源于网络:
- 几个主要的类说明:
- DispatcherServlet:前端控制器,是SpringMVC全局请求分发器,一个请求匹配前端控制器 DispatcherServlet 的请求映射路径(在 web.xml中指定), WEB 容器将该请求转交给 DispatcherServlet 处理
- DispatcherServlet 接收到请求后, 将根据 请求信息 交给 处理器映射器 (HandlerMapping)
- HandlerMapping 根据用户的url请求 查找匹配该url的 Handler,并返回一个执行链
- DispatcherServlet 再请求 处理器适配器(HandlerAdapter) 调用相应的 Handler 进行处理并返回 ModelAndView 给 DispatcherServlet
- DispatcherServlet 将 ModelAndView 请求 ViewReslover(视图解析器)解析,返回具体 View
- DispatcherServlet 对 View 进行渲染视图(即将模型数据填充至视图中)
- 相关类说明:
- DispatcherServlet 将页面响应给用户
- DispatcherServlet:前端控制器
- HandlerMapping:处理器映射器
- Handler:处理器
- HandlAdapter:处理器适配器
- ViewResolver:视图解析器
- View:视图
2.源码分析流程图
上图是后续本文分析源码的流程
3.源码分析
3.1 SpringMVC入口分析
首先请求进来,会先经过一系列过滤器,最后到底FrameworkServlet的service方法,该类是DispatcherServlet的父类,也可以说是先到DispatcherServlet,下面看以下service方法到底会做那些操作:
- 判断请求类型是否是null、PATCH,如果是则直接进入processRequest方法,否则调用父类service即httpServlet
FrameworkServlet:
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//这里获取请求的类型,判断请求是否是null或者Patch如果是直接进入ProcessRequest方法,否则调用父类的service方法
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
//调用父类HttpServlet
super.service(request, response);
}
}
复制代码
HttpServlet中的service: HttpServlet的service主要操作: 1.判断请求类型,进行调用不同的请求类型的处理方法doGet、doPost等
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取请求方法
String method = req.getMethod();
//判断类型如果是get请求则调doGet
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
ifModifiedSince = -1;
}
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
//判断类型如果是HEAD请求则调doHead
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
}
省略部分....
}
复制代码
具体的doPost、doGet等方法其实在FrameworkServlet中实现的,最终不同的请求类型调用不同方法做完处理之后都会调用processReqest方法 下面简单看FrameworkServlet中doGet和doPost中的实现:
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//最终调用processRequest方法
processRequest(request, response);
}
/**
* Delegate POST requests to {@link #processRequest}.
* @see #doService
*/
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//最终调用processRequest方法
processRequest(request, response);
}
复制代码
3.2 ProcessRequest方法分析
该方法主要三件事:
- 初始化web管理器以及注册回调拦截器
- 调用doService执行具体逻辑
- 通过事件推送吧结果输出
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
try {
//该方法主要操作在于doService方法
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
logResult(request, response, failureCause, asyncManager);
//执行完成后进行相关结果处理
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
复制代码
在调用的doService方法核心逻辑: 1.初始化一些可用的处理器以及视图对象 2.调用真正分发的doDispatch方法 下面直接看doDispatch方法: doDispatch方法作用:
1.通过调用getHandler方法获取包含了HandlerMapping的HandlerExecutionChain对象
2.从HandlerExecutionChain对象中通过getHandler获取对应的handlerMethod,然后根据handlerMethod获取handlerAdapter
3.执行HandlerExecutionChain的所有拦截器的前置方法preHandle
4.通过handlerAdapter调用handle去执行具体处理方法,最终是调用到某个controller方法
5.执行handlerExecutionChain中的所有拦截器的后置处理方法applyPostHandle
6.调用processDispatchResult方法处理请求分发结果,主要是处理视图解析等操作
7.最后处理资源清理工作
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
//并不是直接处理的handler,而是handler的执行链,里面会有符合条件的拦截器
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 这个是核心操作,它主要根据请求url去匹配对应的handlerMapping,然后经过一系列处理获取到handler执行链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 此处调用主要是寻找handler的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//调用handler执行链的所有拦截器的前置处理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// handler正在执行的方法,即某个controller中的某个方法,然后处理结果返回一个ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//执行handler执行链的所有拦截器的后置处理器
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//处理请求分发执行后的结果,主要是视图解析等一系列操作
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
//最后处理资源清楚工作
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
复制代码
那么getHandler是如何获取到handler执行链的? 它其实是通过遍历DispatcherServlet中所有的HandlerMapping,然后通过handlerMapping中的getHandler获取handler执行链,但handlerMapping主要分为两种:
- AbstractUrlHandlerMapping:应对xml中编写的url
- AbstractHandlerMethodMapping 应对注解形式的controller
而handlerMapping中getHandler方法中主要是进行几个操作:
- 调用getHandlerInternal方法,该方法是抽象方法,具体实现在对应的handlermapping子类中,主要分为两类:AbstractHandlerMethodMapping这个是基于@RequetMapping等注解形式的handlerMapping,AbstractUrlHandlerMapping类主要是处理可配置的url查找、程序映射到url的等操作比XML里配置一个/hello到对应实现类等可配置url处理。根据reuqest的url调用AbstractUrlHandlerMapping获取handler名称或者对应的handler的Bean名称,这种是基于可配置的url,另外一种是基于方法匹配即controller中定义的每个方法会调用AbstractHandlerMethodMapping
- 调用getHhandlerInternal后获取到对应handler的bean名称或者实例对象,调用getHandlerExecutionChain构建成HandlerExecutionChain
- 把获取到的handler放到handlerExecutionChain执行链上
- 判断是否需要处理跨越问题,如果需要则根据跨域配置以及现有的handler执行链重新构建获取一个新的执行链
然后HandlerMaping中的getHandler方法源码如下:
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//获取handler
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
//根据handler和request获取到具体的handler执行链
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
//跨域处理
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
复制代码
下面分析一些基于注解形式的handler获取: AbstractHandlerMethodMapping的getHandlerInternal方法作用: 1.通过UrlPathHelper工具类根据request获取(url)lookupPath即获取handler的key 2.获取mappingRegistry对象的读锁,避免并发问题还在注册Mapping映射时,出现在获取handler的情况(不知道有没有理解错误) 3.调用lookupHandlerMethod(lookupPath, request);获取handlerMethod对象,该对象包含了方法的参数、返回值、注解等。该方法主要是根据lookupPath即url从MappingRegistry中获取对应的RequetsMappingInfo信息,然后根据映射信息以及url等一些列操作获取到最佳匹配的handlerMethod 4.根据获取到的HandlerMethod对象创建对应的解析器Bean,然后返回 5.解锁
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//通过工具类获取的url这里是lookupPath
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
//获取读锁,避免还早注册,然后这边在读取
this.mappingRegistry.acquireReadLock();
try {
//通过lookupPath湖区哦到对应的handlerMethod,handlerMetho里包含handler
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
//
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
//然后释放锁
this.mappingRegistry.releaseReadLock();
}
}
复制代码
接着看一下getHandlerExecutionChain是如何生成handler执行链的
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
//遍历所有拦截器
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
//通过匹配的区别增加到拦截器的list里保存起来,然后返回
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
复制代码
handler执行链获取到之后,然后进行获取handler的适配器: 遍历所有的handlerAdapters找到对应的adapter,一般是RequestMappingHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
//如果支持则直接返回
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
复制代码
接着就是执行拦截器的前置处理了,其实就是遍历该handler执行链上的所有拦截器的前置处理方法:
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//遍历执行
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
复制代码
接着是handler执行handle方法做具体逻辑方法调用
AbstractHandlerMethodAdapter:
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
调用子类的方法
return handleInternal(request, response, (HandlerMethod) handler);
}
复制代码
RequestMappingHandlerAdapter:
1.调用invokeHandlerMethod方法执行处理
2.判断请求头有没有缓存控制,有则进行缓存处理
@Override
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) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
//核心处理逻辑方法
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
//核心处理逻辑方法
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
//核心处理逻辑方法
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
复制代码
下面方法是具体handler执行并且返回ModelAndView,主要做了以下几个操作: 该方法是主要handler处理逻辑: 1.先handlerMethod获取到web数据绑定工厂 2.获取模型工厂 3.根据handlerMethod创建出ServletInvocableHandlerMethod对象,该对象还需要设置一下handlerMethod的参数解析器、返回值处理器、数据绑定工厂、参数名处理对象,是一个具有执行、解析、处理参数一个执行方法对象. 4.servletInvocableHandlerMethod对象调用invokeAndHandle方法执行,最底层是基于反射执行Method来处理的 5.执行完成后通过返回值处理器returnValueHandlers处理返回值,然后调用getModelAndView方法获取到ModelAndView
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//获取数据绑定工厂\模型解析以及参数解析器、返回值处理handler等等
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
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);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
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;
}
//处理结果并且返回对应的ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
复制代码
返回对应的ModelAndView之后,接着就是执行对应拦截器的后置处理方法, 最后就是调用processDispatchResult方法处理结果,该方法大致做了以下几点: 该方法主要做两件事:
1.判断前面执行过程中有没有异常,则遍历调用DispatcherServlet中所有的异常解析处理器HandlerExceptionResolver的resolveException(所有的异常解析处理器都必须实现改接口或者实现AbstractHandlerExceptionResolver的抽象子类,平常自定义异常解析可以基于上面者两个类做扩展)
2.没有异常的通过调用render方法处理视图,分两种请情况,前面获得的modeAndViews是否指定了视图名称,如果是则通过视图解析器处理比如:BeanNameViewResolver\FreeMarkerViewResolver、InternalResourceViewResolver等,如果不是则从ModeAndView获取到对应的视图,里面有多种视图包括处理json的MappingJackson2JsonView以及模板引擎的FreeMarkerView,也可以自定义视图处理,可以通过实现AbstractView或者想简单扩展json视图可以通过继承AbstractJackson2View来实现。
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
//异常视图处理
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
//这里是正常视图处理
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
复制代码
由于篇幅有限,其他一些方法可以通过流程图以及具体源码类去了解