Spring MVC 流程梳理
大约 9 分钟SpringSpring
Spring MVC 流程梳理
Spring MVC 是一个基于 servlet 的 web 框架,所有的 web 请求会先到 DispatcherServlet
, 由 DispatcherServlet 根据请求的信息进行分配处理。
Spring boot autoconfigure 中的自动配置类 DispatcherServletAutoConfiguration
会自动的将DispatcherServlet
放入到容器中,Spring 在启动的过程中,会将该 Servlet 注册到 Tomcat 的 context 中。

1 代码流程
web 容器通过 Servlet
的 service
方法作为入口, 传入 request
和 response
对象。
void service(ServletRequest req, ServletResponse res)
中间的抽象类 FrameworkServlet
实现了一些骨架方法,最终请求会来到 DispatchServlet
类中的 doDispatch()
方法里。
// org.springframework.web.servlet.DispatcherServlet
/**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
// 异步处理管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 是否是Multipart请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
// 根据当前请求获取HandlerExecutionChain
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 根据处理器获取对应的adapter
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;
}
}
// 调用拦截器的applyPreHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 实际处理请求
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 拦截器的postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 处理结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 拦截器的afterCompletion方法
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) {
// 对于异步的请求,调用拦截器的afterConcurrentHandlingStarted方法
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
1.1 获取 handler
根据请求的 request
获取执行的执行链。
// org.springframework.web.servlet.DispatcherServlet#getHandler
/**
* Return the HandlerExecutionChain for this request.
* <p>Tries all handler mappings in order.
* @param request current HTTP request
* @return the HandlerExecutionChain, or {@code null} if no handler could be found
*/
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
// org.springframework.web.servlet.handler.AbstractHandlerMapping
/**
* Look up a handler for the given request, falling back to the default
* handler if no specific one is found.
* @param request current HTTP request
* @return the corresponding handler instance, or the default handler
* @see #getHandlerInternal
*/
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 根据请求的url、method等获取对应的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执行链
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 (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
/**
* Build a {@link HandlerExecutionChain} for the given handler, including
* applicable interceptors.
* <p>The default implementation builds a standard {@link HandlerExecutionChain}
* with the given handler, the handler mapping's common interceptors, and any
* {@link MappedInterceptor MappedInterceptors} matching to the current request URL. Interceptors
* are added in the order they were registered. Subclasses may override this
* in order to extend/rearrange the list of interceptors.
* <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a
* pre-built {@link HandlerExecutionChain}. This method should handle those
* two cases explicitly, either building a new {@link HandlerExecutionChain}
* or extending the existing chain.
* <p>For simply adding an interceptor in a custom subclass, consider calling
* {@code super.getHandlerExecutionChain(handler, request)} and invoking
* {@link HandlerExecutionChain#addInterceptor} on the returned chain object.
* @param handler the resolved handler instance (never {@code null})
* @param request current HTTP request
* @return the HandlerExecutionChain (never {@code null})
* @see #getAdaptedInterceptors()
*/
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 将请求路径对应的拦截器放入handler中
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
this.handlerMappings
包括所有HandlerMapping
的实现类。AbstractHandlerMapping
根据请求的url
和http method
(Controller 中的RequestMapping
注解)找到对应的处理器(即 Controller 中的方法)。AbstractHandlerMapping
同时也会根据请求 url 找出所有满足当前请求的拦截器。- 将
handler、interceptor
组合生成一个HandlerExecutionChain
对象并返回。
1.2 请求适配器
根据handler获取对应的adapter,RequestMappingHandlerAdapter
。
// org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter
/**
* Return the HandlerAdapter for this handler object.
* @param handler the handler object to find an adapter for
* @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
// 找出adapter
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");
}
// org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports
/**
* This implementation expects the handler to be an {@link HandlerMethod}.
* @param handler the handler instance to check
* @return whether or not this adapter can adapt the given handler
*/
@Override
public final boolean supports(Object handler) {
// 是否是HandlerMethond
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
1.3 拦截器 applyPreHandle
依次执行所有的拦截器的
preHandle
方法。所有
prehandler
都返回true
时,继续执行后续处理流程。其中一个
preHandle
返回false
时。停止执行后续的拦截器。
同时执行
triggerAfterCompletion
方法。- 倒序执行已经执行过的处理器的
afterCompletion
方法。 - 不包括当前返回false的拦截器。
- 倒序执行已经执行过的处理器的
不执行后续处理流程。
// org.springframework.web.servlet.DispatcherServlet#doDispatch
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle
/**
* Apply preHandle methods of registered interceptors.
* @return {@code true} if the execution chain should proceed with the
* next interceptor or the handler itself. Else, DispatcherServlet assumes
* that this interceptor has already dealt with the response itself.
*/
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;
}
// 执行成功后index加1
this.interceptorIndex = i;
}
}
return true;
}
// org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion
/**
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
* has successfully completed and returned true.
*/
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);
}
}
}
}
1.4 执行 handler
- 使用
HandlerMethodArgumentResolver
将请求的数据解析为调用方法的参数。 - 调用方法处理。
- 使用
HandlerMethodReturnValueHandler
对返回的对象解析。 - 生成
ModelAndView
(如果返回类型需要)。
// org.springframework.web.servlet.DispatcherServlet#doDispatch
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle
/**
* This implementation expects the handler to be an {@link HandlerMethod}.
*/
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
// org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
// 在session范围内同步执行
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
// 执行处理器
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
// org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod
/**
* Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
* if view resolution is required.
* @since 4.2
* @see #createInvocableHandlerMethod(HandlerMethod)
*/
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 封装request 和 response
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 创建InvocableHandlerMethod,并保存一些配置
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);
// 视图容器, model 和 view相关数据
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);
}
// 执行handler
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 返回ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
// org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
/**
* Invoke the method and handle the return value through one of the
* configured {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers}.
* @param webRequest the current request
* @param mavContainer the ModelAndViewContainer for this request
* @param providedArgs "given" arguments matched by type (not resolved)
*/
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 执行处理,获取返回结果
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// 解析返回值
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
// org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest
/**
* Invoke the method after resolving its argument values in the context of the given request.
* <p>Argument values are commonly resolved through
* {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}.
* The {@code providedArgs} parameter however may supply argument values to be used directly,
* i.e. without argument resolution. Examples of provided argument values include a
* {@link WebDataBinder}, a {@link SessionStatus}, or a thrown exception instance.
* Provided argument values are checked before argument resolvers.
* <p>Delegates to {@link #getMethodArgumentValues} and calls {@link #doInvoke} with the
* resolved arguments.
* @param request the current request
* @param mavContainer the ModelAndViewContainer for this request
* @param providedArgs "given" arguments matched by type, not resolved
* @return the raw value returned by the invoked method
* @throws Exception raised if no suitable argument resolver can be found,
* or if the method raised an exception
* @see #getMethodArgumentValues
* @see #doInvoke
*/
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 解析参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 调用方法
return doInvoke(args);
}
/**
* Get the method argument values for the current request, checking the provided
* argument values and falling back to the configured argument resolvers.
* <p>The resulting array will be passed into {@link #doInvoke}.
* @since 5.1.2
*/
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
// 通过resolvers对参数进行解析并返回
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
// Leave stack trace for later, exception may actually be resolved and handled...
if (logger.isDebugEnabled()) {
String exMsg = ex.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw ex;
}
}
return args;
}
1.5 拦截器 postHandle
倒序依次执行拦截器的postHandle方法。
// org.springframework.web.servlet.DispatcherServlet#doDispatch
mappedHandler.applyPostHandle(processedRequest, response, mv);
// org.springframework.web.servlet.HandlerExecutionChain#applyPostHandle
/**
* Apply postHandle methods of registered interceptors.
*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
1.6 处理结果
- 如果
handler
处理过程中出现异常,此处进行异常处理。 - 如果存在
ModelAndView
对象,则对视图进行渲染。 - 最后倒序执行所有拦截器的
afterCompletion
。
// org.springframework.web.servlet.DispatcherServlet#doDispatch
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
// org.springframework.web.servlet.DispatcherServlet#doDispatch
/**
* Handle the result of handler selection and handler invocation, which is
* either a ModelAndView or an Exception to be resolved to a ModelAndView.
*/
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);
}
}
// Did the handler return a view to render?
// render
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;
}
// 执行拦截器的afterCompletion方法
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
至此,一个简单的 http 请求的处理便完成了,客户端会通过 response
中的数据进行渲染展示。
2 流程图
