文章目录
MVC请求处理
DispatcherServlet
Tomcat根据Mapping,将请求派发到对应的context,如果这个web应用是一个MVC项目,则该context中有一个DispatcherServlet,请求经过一系列Filter后,会传递给该Servlet。
需要使用到的组件:
- WebAsyncManager:异步请求处理器
- LocaleResolver:本地化解析器
- ThemeResolver:主题解析器
- ThemeSource:主题源
- MessageSource:消息源
- FlashMapManager:闪存管理器,用于提供重定向跨请求传递Model参数
- MultipartResolver:多块请求处理器
- List< HandlerMapping>:处理器映射集合
- List< HandlerAdapter>:处理器适配器集合
- List< HandlerExceptionResolver>:异常处理器集合
- ViewNameTranslator:视图名转换器
- List< ViewResolver>:视图解析器列表
这些组件会在DispatcherServlet创建MVC子容器的时候进行初始化。在调用DispatcherServlet的init()方法时,会创建一个mvc的子容器,同时初始化这些组件。
DispatcherServlet的父类FrameworkServlet持有一个WebApplicationContext的对象,该对象表示一个mvc容器。在init()过程中,会调用FrameworkServlet的onRefresh()方法,该方法是FrameworkServlet自定义的,和Spring中的onRefresh方法无关。
DispatcherServlet重写了onRefresh()方法
protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
1.1 DispatcherServlet的service()方法
该Servlet继承了HttpServlet,会调用其Service()方法。DispatcherServlet并没有重写该方法,所以会调用抽象父类HttpServlet中的该方法。该方法根据不同的请求,调用不同的处理方法。
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
//没有开启http缓存
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
//判断是否支持http缓存支持
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
//请求方法不被支持
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
1.2 do**方法
根据不同的请求会调用doXX方法,DispatcherServlet的直接父类FrameworkServlet重写了这些方法,所以会调用FrameworkServlet中的do系列方法。该类中所有的do系列方法最后都调用了processRequest()
方法,do系列方法的区别是不同请求需要进行一些不同的判断。
1.3 FrameworkServlet的processRequest()
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//当前时间
long startTime = System.currentTimeMillis();
//失败信息
Throwable failureCause = null;
//保存本地上下文,用于在请求完成后恢复原来的上下文
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
//根据请求创建新的本地上下文,本地上下文包含请求的地区信息、时区信息等
LocaleContext localeContext = this.buildLocaleContext(request);
//和上面类似,保存属性
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
//请求属性包括Request的属性和Session的属性
ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
//获取异步管理器,用于管理异步响应结果
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor());
//将新创建的本地上下文和属性放入ThreadLocal中,供当前整个请求过程中使用
this.initContextHolders(request, localeContext, requestAttributes);
try {
//真正的处理请求入口,DispatcherServlet重写了该方法
this.doService(request, response);
} catch (IOException | ServletException var16) {
failureCause = var16;
throw var16;
} catch (Throwable var17) {
failureCause = var17;
throw new NestedServletException("Request processing failed", var17);
} finally {
//还原,将ThreadLocal恢复为原来的设置
this.resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
this.logResult(request, response, (Throwable)failureCause, asyncManager);
this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
}
}
1.4 DisPatcherServlet的doService()
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
this.logRequest(request);
//属性快照,只有是一个请求中包含几个子请求的时候才需要保存上一个请求的属性,防止覆盖
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap();
Enumeration attrNames = request.getAttributeNames();
label95:
while(true) {
String attrName;
do {
if (!attrNames.hasMoreElements()) {
break label95;
}
attrName = (String)attrNames.nextElement();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
//将MVC的应用上下文保存到request中
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
//将本地化解析器放入请求
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
//主题解析器放入请求
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
//主题源,包含很多组css等资源的组合,相当于网页换肤功能
request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
//FlashMap用于处理重定向请求的参数传递
if (this.flashMapManager != null) {
//接收从别的请求重定向到该请求的请求参数
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
//同时设置一个用于输出的FlashMap,用于本请求重定向到别的请求
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
try {
//核心,派发请求
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
1.5 doDispatch()
该过程的步骤:
- 预处理多块请求
- 获取handler
- 获取HandlerAdapter
- 处理Http缓存
- 执行拦截器的前置逻辑
- handler处理请求
- 结果的视图名处理
- 执行后置处理
- 处理返回值和响应
- 执行完成拦截器链(异常处理逻辑)
- 清理资源
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;//处理器执行链
boolean multipartRequestParsed = false; //是否是多块请求,比如文件上传
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
//请求处理结果
ModelAndView mv = null;
Object dispatchException = null;
try {
//判断是否是多块请求,如果是返回一个新的请求
processedRequest = this.checkMultipart(request);
//如果processedRequest和request指向同一个对象,则不是多块请求
multipartRequestParsed = processedRequest != request;
//从HandlerMapping中寻找Handler
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
//从HandlerAdapter中寻找处理当前请求Handler的适配器
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
//如果是Get请求或者Head请求,判断请求头中的lastModified属性是否改变了
//没改变,则直接返回,让浏览器从缓存中取数据
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
//如果lastModified是-1,则继续往下执行
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
//执行handler的前置拦截器,如果返回false,则直接返回,请求被拦截了
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//调用HandlerAdapter,将请求、响应、Handler传入,进行请求的处理。
//返回一个ModelAndView对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//判断是否开启异步处理,如果是的话,后序步骤通过异步处理,当前线程直接返回
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//应用默认的视图名,如果返回的ModelAndView对象不包含视图名或者视图的话
this.applyDefaultViewName(processedRequest, mv);
//执行handler拦截器的后置处理逻辑,顺序为从尾部到头部
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
//将请求的结果进行处理
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
//如果发生异常,执行拦截器的对应方法
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
//释放资源
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
下面分别对应1.5中的一部分
1.6 getHandler(handler的查找)
从HandlerMapping中查找可以处理当前请求的Handler,mapping可能有多种,例如在spring mvc(1)中说的按BeanName映射或者@RequestMapping。
查找出来的handler会封装为一个HandlerExecutionChain对象,包含拦截器和最终的handler处理逻辑
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
//从对应HandlerMapping中获取处理该请求的执行链
//主要分析RequestMappingHandlerMapping
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
-------AbstractHandlerMapping类
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = this.getHandlerInternal(request);
if (handler == null) {
handler = this.getDefaultHandler();
}
if (handler == null) {
return null;
} else {
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.obtainApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Mapped to " + handler);
} else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
this.logger.debug("Mapped to " + executionChain.getHandler());
}
if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null;
CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
config = config != null ? config.combine(handlerConfig) : handlerConfig;
executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
}
1.7 HandlerAdapter的查找
根据Handler的执行链,获取适配器。
通过@RequestMapping方式映射的handler会被封装为HandlerMethod对象,要寻找的就是支持处理HandlerMethod对象的适配器。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next();
//遍历所有的Adapter,找出支持当前handler的适配器
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");
}
1.8 拦截器的前置处理
执行HandlerExecutionChain中拦截器的前置处理
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
}
return true;
}
1.9 处理请求
调用对应适配器的handler()方法,@RequestMapping对应的适配器为RequestMappingHandlerAdapter。
1.10视图名设置
如果handler执行完后,返回的结果不包含视图或者视图名,为其设置默认的视图名
private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
if (mv != null && !mv.hasView()) {
String defaultViewName = this.getDefaultViewName(request);
if (defaultViewName != null) {
mv.setViewName(defaultViewName);
}
}
}
--------------------------
//通过viewNameTranslator获取默认的视图名
@Nullable
protected String getDefaultViewName(HttpServletRequest request) throws Exception {
return this.viewNameTranslator != null ? this.viewNameTranslator.getViewName(request) : null;
}
1.11拦截器的后置处理
和前置处理类似,需要注意是从链尾执行到链头
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = this.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.12结果的最终处理
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
//错误视图标记
boolean errorView = false;
//如果发生了异常,将异常中封装的错误视图或者直接创建一个错误视图赋予参数mv
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
this.logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException)exception).getModelAndView();
} else {
//其他类型的异常,先根据异常类型获得handler
Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
//执行异常处理
mv = this.processHandlerException(request, response, handler, exception);
errorView = mv != null;
}
}
//如果mv不为空而且没有被标记为被清理
if (mv != null && !mv.wasCleared()) {
//进行视图渲染
this.render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else if (this.logger.isTraceEnabled()) {
this.logger.trace("No view rendering, null ModelAndView returned.");
}
//如果没有开启异步处理
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
//执行拦截器的请求完成方法
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
}
}
}