Spring处理请求方法委托给了processRequest(request,response);
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
1.FrameworkServlet.processRequest(HttpServletRequest request,HttpServletResponse response);
/**
* 处理此请求,无论结果如何都发布事件。
* <p>实际的事件处理由{@link #doService}模板方法执行。
*/
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//记录当前时间
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
//返回当前线程的LocaleContext
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
//构建当前语言环境的上下文
LocaleContext localeContext = buildLocaleContext(request);
//返回当前线程绑定的RequestAttributes
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
//获取request请求的WebAsyncManager或者new一个
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
//绑定localeContext和requestAttributes到当前线程上
//为什么绑定到当前线程上???
//在spring mvc中,为了随时都能取到当前请求的request对象,可以通过RequestContextHolder
// 的静态方法getRequestAttributes()获取Request相关的变量,如request, response等。
// LocaleContext当然效果同理
initContextHolders(request, localeContext, requestAttributes);
try {
//委托DipsatcherServlet实现
doService(request, response);
}
catch (ServletException ex) {
failureCause = ex;
throw ex;
}
catch (IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
//重新绑定之前的localeContext和requestAttributes到线程上
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
主要就是构造当前request请求的LocaleContext和ServletRequestAttributes对象通过initContextHolders(request, localeContext, requestAttributes);方法绑定到线程,为了随时都能取到当前请求的request对象,可以通过RequestContextHolder 的静态方法getRequestAttributes()获取Request相关的变量,如request, response等。 // LocaleContext当然效果同理;然后方法委托给了doService(request,response);恢复线程先前绑定的LocaleContext和ServletRequestAttributes对象,最后就是发布请求处理处理完成的事件
private void publishRequestHandledEvent(
HttpServletRequest request, HttpServletResponse response, long startTime, Throwable failureCause) {
//请求结束后发布个事件
if (this.publishEvents) {
// Whether or not we succeeded, publish an event.
long processingTime = System.currentTimeMillis() - startTime;
// 获取状态码
int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1);
// 发布事件
this.webApplicationContext.publishEvent(
new ServletRequestHandledEvent(this,
request.getRequestURI(), request.getRemoteAddr(),
request.getMethod(), getServletConfig().getServletName(),
WebUtils.getSessionId(request), getUsernameForRequest(request),
processingTime, failureCause, statusCode));
}
}
2.使用监听器监听ServletRequestHandledEvent事件
定义ServletRequestHandledEventListener实现ApplicationListener
/**
* @author 周宁
* @Date 2019-08-20 19:18
*/
public class ServletRequestHandledEventListener implements ApplicationListener<ServletRequestHandledEvent> {
@Override
public void onApplicationEvent(ServletRequestHandledEvent event) {
System.out.println(event.getRequestUrl());
}
}
在applicationContext.xml中配置ServletRequestHandledEventListener
<bean id="servletRequestHandledEventListener" class="org.springframework.studymvc.event.ServletRequestHandledEventListener"/>
3.DispatcherServlet.doService(HttpServletRequest request,HttpServletResponse response);
/**
* 将DispatcherServlet特定的请求属性和委托公开给{@link #doDispatch}以进行实际调度。
*/
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
// 在包含requeset请求的情况下保留请求属性快照
// 能够在包含之后恢复原始属性。
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
//request请求快照
attributesSnapshot = new HashMap<String, Object>();
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));
}
}
}
// Make framework objects available to handlers and view objects.
// 使框架对象可供处理程序和视图对象使用。
// 设置request的上下文
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
// 设置request的国际化
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
// 设置request的theme属性
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
// 获取ThemeSource
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
// 实现请求的重定向
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(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// 如果是include,则还原原始属性快照。
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
该方法主要是给当前request对象添加一系列的attribute;我们后面可以通过request.getAttribute(attributeName)获取到啦;
这里主要难理解的是WebUtils.isIncludeRequest(request)这里的方法,我们需要知道的是jsp的本质就是servlet
<jsp:incluede page="index.jsp"/>
这条指令是指在一个页面中嵌套了另一个页面,那么我们知道JSP在运行期间是会被编译成相应的Servlet类来运行的,所以在Servlet中也会有类似的功能和调用语法,这就是RequestDispatch.include()方法。 那么在一个被别的servlet使用RequestDispatcher的include方法调用过的servlet中,如果它想知道那个调用它的servlet的上下文信息该怎么办呢,那就可以通过request中的attribute中的如下属性获取:
javax.servlet.include.request_uri
javax.servlet.include.context_path
javax.servlet.include.servlet_path
javax.servlet.include.path_info
javax.servlet.include.query_string
4.DispatcherServlet.doDispatch(HttpServletRequest request,HttpServletResponse response);
/**
* 处理实际调度到处理程序。
* <p>处理程序将通过按顺序应用DispatcherServlet的HandlerMappings来获得。
* 将通过查询servlet安装的HandlerAdapter来获取HandlerAdapter,以找到支持处理程序类的第一个。
* <p>所有HTTP方法都由此方法处理。 由HandlerAdapters或处理程序自行决定哪些方法可以接受。
*
* @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 {
//转换当前request为MultipartHttpServletRequest
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 确定当前请求的处理程序。
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
//如果未找到
noHandlerFound(processedRequest, response);
return;
}
// 确定当前请求的处理程序适配器。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 处理最后修改的标头,如果处理程序支持。
String method = request.getMethod();
boolean isGet = "GET".equals(method);
//请求头方法支持last-modified头处理
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//应用前置拦截器,前置处理器返回false则程序退出
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 实际调用处理器的方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//7.如果当前请求是并发处理,直接返回
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//为返回值设定默认视图名,如果当前返回值中不包含视图名的话
applyDefaultViewName(processedRequest, mv);
//注册的拦截器的后处理方法应用
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) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
} catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
} finally {
//
if (asyncManager.isConcurrentHandlingStarted()) {
// 异步请求的条件下触发AsyncHandlerInterceptor.afterConcurrentHandlingStarted方法
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else {
// 清理多部分请求使用的任何资源。
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
方法主要流程为:
- a.使用multipartResolver处理文件上传请求的request转换为MultipartHttpServletRequest
- b.通过我们初始化的handlerMappings获取当前request请求的HandlerExecutionChain(处理程序执行链,由处理程序对象和任何处理程序拦截器组成。)
- c.HandlerExecutionChain不存在或者里面的处理程序Handler为null,设置适当的HTTP响应状态码
- d.通过配置的handlerAdapters找到合适的HandlerAdapter
- e.判断请求是否支持last-modified
- f.应用注册的HandlerInterceptors的preHandle方法,如果返回false,则停止处理该请求并调用HandlerInterceptors的triggerAfterCompletion方法
- g.使用HandlerAdapter调用实际的请求处理方法并返回一个ModelAndView对象
- h.设置视图的默认名称
- i.应用HandlerInterceptor的postHandle方法
- j.捕获从a-i过程中的异常并将请求处理的结果呈现出来并最终调用HandlerInterceptors的afterCompletion方法!!!
- k.如果整个流程出现了异常那么调用HanlderInterceptors的afterCompletion方法
- l.清楚上传文件使用的任何资源
5.SpringMVC整体流程