目录
3.3 DispatcherServlet 分发请求(核心处理逻辑)
3.4 HandlerAdapter 调用流程(RequestMappingHandlerAdapter)—— 调用处理器方法
3.5 HandlerAdapter 调用流程(RequestMappingHandlerAdapter)—— 处理器返回处理结果
写文章不易,时序图均为自研,转载请标明出处。
同时,如果你喜欢我的文章,请关注我,让我们一起进步。
一、概述
这篇博文的主要内容就是根据源码来解析 SpringMVC 中对于请求的处理流程,因为 SpringMVC 中对于请求的处理流程非常的繁杂,代码量也是非常的多,为了整个解析的过程清晰一点,我尽量用完全代码注释的方式来完成这篇博文,同时为了便于大家理解整个流程,我在开头提供了第一版的流程图,在源码解析完成后提供了方法调用的时序图,并且在最后的内容总结中梳理了整个流程的主体逻辑,注意这里是主体,因为如果将每一个部分都展开来将实在太多了,下面开始正文。
二、流程图(第一版)
三、源码分析
3.1 DispatcherServlet 接收请求
// FrameworkServlet.class
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取请求方法
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
// 如果请求方法为 PATCH 或者为空则调用 processRequest 进行处理
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
// 否则直接调用父类 HttpServlet 的 service 方法进行处理
super.service(request, response);
}
}
// FrameworkServlet.class
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 当请求方法为 GET 时 HttpServlet 调用到子类 FrameworkServlet 中的 processRequest 方法进行处理
processRequest(request, response);
}
3.2 DispatcherServlet 处理请求
// FrameworkServlet.class
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
// 获取与当前线程关联的 LocaleContext(主要用于处理完请求后通过 resetContextHolders 恢复状态)
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
// 为给定请求构建 LocaleContext ,并将请求的主要语言环境设置为当前语言环境
LocaleContext localeContext = buildLocaleContext(request);
// 获取绑定到当前线程的 RequestAttributes(主要用于处理完请求后通过 resetContextHolders 恢复状态)
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
// 考虑到预先绑定的属性(及其类型),为给定的请求构建 ServletRequestAttributes(可能还包含对响应的引用)
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
// 获取当前请求的 WebAsyncManager,如果找不到则创建并将其与请求关联
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
// 在给定键(ServletName)下注册一个 CallableProcessingInterceptor
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
// 初始化 ContextHolder(LocaleContextHolder 和 RequestContextHolder)
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 {
// 恢复当前线程 ContextHolder 的初始状态
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
logResult(request, response, failureCause, asyncManager);
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
// 初始化 ContextHolder
private void initContextHolders(HttpServletRequest request, @Nullable LocaleContext localeContext, @Nullable RequestAttributes requestAttributes) {
if (localeContext != null) {
LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
}
if (requestAttributes != null) {
RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
}
}
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(request);
// 在 include 的情况下,保留请求属性的快照,以便能够在 include 之后恢复原始属性
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// 为 Request 请求添加 Spring Web 容器引用以及各种解析器
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
// 为 Request 请求添加 FlashMap 和 flashMapManager 属性值(属性作用在上面介绍过)
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
try {
// 调用 doDispatch 进行请求分发工作
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// 在 include 的情况下,恢复原始属性快照
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
3.3 DispatcherServlet 分发请求(核心处理逻辑)
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
// 获取当前线程的 WebAsyncManager
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 如果存在 Multipart 解析器且当前请求尚未被解析,则将请求转换为 Multipart 请求
// 否则如果未设置 Multipart 解析器则直接使用原始请求
processedRequest = checkMultipart(request);
// 判断原始请求是否被转换成了 Multipart 请求
multipartRequestParsed = (processedRequest != request);
// 步骤一:获取当前请求的处理器(handler)
mappedHandler = getHandler(processedRequest);
// 如果当前请求不存在处理器则设置适当的 HTTP 响应状态然后直接返回
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 步骤二:获取当前请求的处理器适配器(HandlerAdapter)
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 如果处理程序支持,则处理最后修改的标头(last-modified)
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 方法会调用已经被注册拦截器的 preHandle 方法
// 如果执行链应该继续执行下一个拦截器或处理器则返回 true
// 反之当该方法返回 false 的时候 DispatcherServlet 假定此拦截器已经处理了响应本身
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 步骤四:实际调用处理器对请求进行处理,返回一个 ModelAndView 对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 步骤五:调用拦截器(HandlerInterceptor)的 postHandle 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 步骤六:处理 handler 选择和 handler 调用的结果
// 该结果可以是 ModelAndView 或要解析为 ModelAndView 的异常
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()) {
// 代替拦截器中的 postHandle 和 afterCompletion 方法
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// 清理 multipart 请求使用的所有资源
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
3.4 HandlerAdapter 调用流程(RequestMappingHandlerAdapter)—— 调用处理器方法
// AbstractHandlerMethodAdapter.class
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
// RequestMappingHandlerAdapter.class
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// 如果需要同步,则在同步块中执行 invokeHandlerMethod
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
// 这里使用了 Session 互斥锁
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// 如果没有可用的 HttpSession 那么就没有必要使用 Session 互斥锁
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// 如果根本不需要 Session 上的同步,那么直接调用 invokeHandlerMethod 方法
mav = invokeHandlerMethod(request, response, handlerMethod);
}
// 处理响应缓存
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 将请求信息和响应信息包装为 ServletWebRequest 实例对象
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 创建可被调用的 ServletInvocableHandlerMethod 对象来包装原始的 HandlerMethod
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);
// 使用异步请求处理方法扩展 NativeWebRequest
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
// 创建用于管理异步请求处理的中央类 WebAsyncManager 并进行属性设置
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
// 配置 AsyncTaskExecutor 用于 startCallableProcessing 方法的并发执行
asyncManager.setTaskExecutor(this.taskExecutor);
// 配置 AsyncWebRequest
asyncManager.setAsyncWebRequest(asyncWebRequest);
// 注册回调拦截器 CallableProcessingInterceptor
asyncManager.registerCallableInterceptors(this.callableInterceptors);
// 注册 DeferredResultProcessingInterceptor
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
// 如果结果值作为并发处理的结果而存在
if (asyncManager.hasConcurrentResult()) {
// 获取并发处理的结果
Object result = asyncManager.getConcurrentResult();
// 获取并发处理开始时保存的其它处理上下文
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
// 清除 asyncManager 中的 concurrentResult 和 concurrentResultContext
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
// 创建一个嵌套的 ServletInvocableHandlerMethod 子类 ConcurrentResultHandlerMethod
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 调用处理请求的方法并将请求包装对象(ServletWebRequest)和数据视图对象(ModelAndViewContainer)传入
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 调用方法并返回执行结果
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 设置响应状态
setResponseStatus(webRequest);
// 省略返回值处理逻辑 ...
}
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 获取方法参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
// 实际调用方法处
return doInvoke(args);
}
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
// 获取到桥接方法并最终通过反射调用方法
return getBridgedMethod().invoke(getBean(), args);
}
...
}
@RequestMapping(value = "/to_login", method = RequestMethod.GET)
public String toLogin(){
return "user_login";
}
3.5 HandlerAdapter 调用流程(RequestMappingHandlerAdapter)—— 处理器返回处理结果
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()) {
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) {
throw ex;
}
}
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// 选择返回值处理器
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
// 判断是否为异步返回值
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
// returnValueHandlers 中所包含的 ReturnValueHandler 如下图
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
// 最简单的情况即我们只返回了一个视图名称,此时返回 ViewNameMethodReturnValueHandler
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
// ViewNameMethodReturnValueHandler.java
public boolean supportsReturnType(MethodParameter returnType) {
Class<?> paramType = returnType.getParameterType();
return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType));
}
// ViewNameMethodReturnValueHandler.java
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue instanceof CharSequence) {
String viewName = returnValue.toString();
// 设置视图名称,该名称后面会由 DispatcherServlet 通过 ViewResolver 解析
mavContainer.setViewName(viewName);
// 判断是否为重定向视图名称(即 viewName.startsWith("redirect:"))
if (isRedirectViewName(viewName)) {
// 如果需要重定向则做好重定向标记
mavContainer.setRedirectModelScenario(true);
}
}
else if (returnValue != null){
// should not happen
throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
...
// 进行请求处理器方法调用
invocableMethod.invokeAndHandle(webRequest, mavContainer);
// 调用结束后返回到这里
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 获取数据和视图
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
// 将 model 中的属性列表添加到 session 的 SessionAttributes 中(级别提升)
modelFactory.updateModel(webRequest, mavContainer);
// 如果请求已经被处理了则直接返回
if (mavContainer.isRequestHandled()) {
return null;
}
// 从返回值容器中获取数据
ModelMap model = mavContainer.getModel();
// 将处理结果封装到 ModelAndView 对象中
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
// isViewReference 直接判断 mavContainer 的 view 属性值是否为 String 类型
// 如果 mavContainer 保存的 view 是一个 View 对象而非 String 则将其直接保存到 ModelAndView 对象中
mav.setView((View) mavContainer.getView());
}
// 重定向逻辑
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
...
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;
}
protected final void prepareResponse(HttpServletResponse response) {
if (this.cacheControl != null) {
applyCacheControl(response, this.cacheControl);
}
else {
// 应用给定的缓存秒数并生成相应的 HTTP 报头
// 即在为正数的情况下允许缓存给定的秒数,如果给定值为 0 则阻止缓存且不执行其他任何操作
applyCacheSeconds(response, this.cacheSeconds);
}
if (this.varyByRequestHeaders != null) {
for (String value : getVaryRequestHeadersToAdd(response, this.varyByRequestHeaders)) {
response.addHeader("Vary", value);
}
}
}
3.6 DispatcherServlet 处理分发结果
// DispatcherServlet.java
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
// 步骤四:调用处理器方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 步骤五:调用拦截器的 postHandle 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
// 步骤六:处理分发后的结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
finally {
// 当并发处理时执行的逻辑
if (asyncManager.isConcurrentHandlingStarted()) {
// 替代拦截器中的 postHandle 和 afterCompletion 方法
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// 清理多部分请求使用的所有资源
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
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()) {
return;
}
if (mappedHandler != null) {
// 视图渲染完成后执行 HandlerInterceptor 拦截器的 afterCompletion 方法
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 获取请求的区域设置,并将其应用于响应
Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// 通过视图名解析视图
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// 如果 ModelAndView 对象包含实际的视图对象则直接获取
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
try {
// 委托给视图对象进行呈现
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
for (ViewResolver viewResolver : this.viewResolvers) {
// 调用 ViewResolver 进行视图解析,解析后的 View 对象结构如下图
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
// 返回成功解析后的视图
return view;
}
}
}
return null;
}
四、时序图(非完全通用版)
@RequestMapping(value = "/to_login", method = RequestMethod.GET)
public String toLogin(){
return "user_login";
}
五、内容总结
5.1 HandlerInterceptor 的调用时机
(1)preHandle:DIspatcherServlet 的 doDispatch 方法中,在执行 HandlerAdapter 的 handle 方法(调用处理器处理请求)之前,通过 HandlerExecutionChain 的 applyPreHandle 方法进行调用;
(2)postHandle:DispatcherServlet 的 doDIspatch 方法中,在执行 HandlerAdapter 的 handle 方法(调用处理器处理请求)之后,通过 HandlerExecutionChain 的 applyPostHandle 方法进行调用;
(3)afterCompletion:在 DispatcherServ 的 processDispatchResult 方法中,在执行完 render 视图渲染后,通过 HandlerExecutionChain 的 triggerAfterCompletion 方法被调用;
5.2 SpringMVC 处理请求流程总结(通用版本)
(1)请求到达服务端时首先调用 FrameworkServlet 中重写 HttpServlet 中的 service 方法,如果请求类型为 PATCH 或者为空则直接调用 FrameworkServlet 中的 processRequest 方法进行处理,否则将调用父类 HttpServlet 中的 service 方法;
(2)当执行了 HttpServlet 的 service 方法后,又会调用到 FrameworkServlet 中重写 HttpServlet 中的 doGet 或 doPost 方法,假设当我们的请求为 GET 类型时,会调用到 FrameworkServlet 中的 doGet 方法,在 doGet 方法中又会调用到它自身的 processRequest 方法,并将请求的 request 和 response 作为参数传入;
(3)在 processRequest 方法中会先进行一些地区和主体的属性获取和设置,然后比较核心的就是调用到 doService 方法来进行业务逻辑的处理;
(4)在 doService 方法中主要进行的就是公开 DIspatcherServlet 中的一些指定的属性(将 localeResolver 位置解析器和 themeResolver 主题解析器或一些其它属性设置到 request 的 attribute 中,使得它们可以通过 request 在全局被访问),还有就是通过调用 doDispatch 方法来进行实际的分发处理;
(5)在 doDispatch 方法中的逻辑比较复杂,所以我们再展开来讲:
5.1 首先通过 getHandler 方法从 HandlerMapping 中获取 HandlerExecutionChain,即处理器执行链(这个链中包括了 Handler 处理器和 HandlerInterceptor 拦截器)。需要注意的这里一般存在三种 HandlerMapping,我们一般最常用的也就是 RequestMappingHandlerMapping(它是从 @Controller 类中的类型和方法级 @RequestMapping 注释创建 RequestMappingInfo 实例),其余的两种因为篇幅原因不在这里赘述;
5.2 然后在通过 getHandlerAdapter 方法获取 Handler 对应的 HandlerAdapter 处理器适配器(每一种 Handler 都对应着不同的 Adapter,比如我们上面提到的那个通过 RequestMappingHandlerMapping 获取到的 Handler 所对应的适配器是 RequestMappingHandlerAdapter);
5.3 调用上面 getHandler 方法所返回的 HandlerExecutionChain 中 HandlerInterceptor 拦截器的 applyPreHandle 方法;
5.4 之后通过调用 HandlerAdapter 的 handle 方法来执行请求所对应的方法(这里的逻辑很复杂,而且不同的 Adapter 有不同的实现逻辑,一般最后是通过反射来实现方法调用的),并接收方法所返回的 ModelAndView 对象;
5.5 调用上面 getHandler 方法所返回的 HandlerExecutionChain 中 HandlerInterceptor 拦截器的 applyPostHandle 方法;
5.6 调用 processDispatchResult 方法来处理分发后的结果,这里的结果包括 handle 方法调用后返回的 ModelAndView 和在上面调用过程中产生的需要转换为 ModelAndView 的 Exception(需要返回给客户端的 Exception),然后会判断当前是否需要进行视图渲染,如果需要则调用 render 方法来进行视图渲染;
5.7 我们现在假设正常情况下存在视图需要被渲染,则在 render 方法又会判断当前的 ModelAndView 中的 ViewName 是否为空,如果不为空证明我们需要去解析视图名称(resolveViewName)得到 View 对象,然后调用 View 对象的 render 方法来让指定的 ViewResolver 来对视图进行解析,但如果 ViewName 为空,那么我们就直接尝试从 ModelAndView 对象中获取 View 对象;
5.8 在 processDispatchResult 方法中完成了 render 视图渲染后,会调用 HandlerExecutionChain 中 HandlerInterceptor 拦截器的 afterCompletion 方法。当其返回到 doDispatch 方法中时,在其 catch 方法中也会执行(保证在异常情况下 afterCompletion 方法也能够被正常执行);
(6)当完成 doDispatch 方法后就会进行层层返回,直到最后将响应发送给客户端;
5.3 心得体会
这篇博文从开始计划,到后面的先查询资料大概理解,然后一步一步的源码调试来捋清业务逻辑大概是有三四天的时间,整个博文花费的时间可能要几十个小时,很多时候就是自己一不小心就陷入了局部的代码逻辑,导致自己的源码越读越多,越读越乱。所以中间经过了好几次的调整,但其实到最后的话自己对于源码分析阶段也不是特别的满意,因为涉及的内容太多了,导致自己不能很好地组织好整篇博文的逻辑,所以在前面和后面分别加了流程图、时序图和总结来弥补一下。
在这个这部分源码阅读的过程中自己也遇到了很多新的技术,也开始慢慢的了解了 SpringMVC 中一些组件的作用,所以在这篇博文完成后,自己会在后面的几天对这篇博文中一带而过的很多技术进行详细的剖析,来加深自己对于 SpringMVC 的理解。
若不给自己设限,则人生中就没有限制你发挥的藩篱。