doXxx方法的(这些方法在FrameworkServlet中被复写),以doGet方法为例:
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
可以看到实际上处理doGet是在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 = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = null;
if (previousAttributes == null || (previousAttributes instanceof ServletRequestAttributes)) {
requestAttributes = new ServletRequestAttributes(request);
}
initContextHolders(request, localeContext, requestAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), getRequestBindingInterceptor(request));
try {
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 {
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()) {
if (logger.isDebugEnabled()) {
logger.debug("Leaving response open for concurrent processing");
}
}
else {
this.logger.debug("Successfully completed request");
}
}
}
if (this.publishEvents) {
// Whether or not we succeeded, publish an event.
long processingTime = System.currentTimeMillis() - startTime;
this.webApplicationContext.publishEvent(
new ServletRequestHandledEvent(this,
request.getRequestURI(), request.getRemoteAddr(),
request.getMethod(), getServletConfig().getServletName(),
WebUtils.getSessionId(request), getUsernameForRequest(request),
processingTime, failureCause));
}
}
}
processRequest的大致逻辑是:
以doService方法为界点,
之前的代码主要就是从request中取出当前的请求对象和属性分别设置到2个ThreadLocal对象中:
LocaleContextHolder和RequestContextHolder,也就是对象和属性都被绑定在当前请求线程上了。
之后的代码主要就是对LocaleContextHolder和RequestContextHolder的请求对象和属性进行解绑,
以及发布一个ServletRequestHandledEvent事件,可以通过注册监听器监听该事件。
可以看到processRequest方法其实也只是做了一些request参数的绑定和解绑,而真正处理请求的方法是doService,
doService是一个抽象方法,由DispatcherServlet重写,代码如下:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + requestUri + "]");
}
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
logger.debug("Taking snapshot of request attributes before include");
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
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());
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()) {
return;
}
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
DispatcherServlet的doService逻辑主要是将前面初始化的容器上下文,本地解析器等springmvc编程元素设置到
request中,供下一步使用,而真正完成请求转发是在doDispatch方法中被处理,它封装了springmvc处理请求转发的所有流程,其定义如下:
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 {
processedRequest = checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
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 (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
doDispatch方法逻辑大概是:
1.mappedHandler = getHandler(processedRequest, false);
遍历之前初始化HandlerMapping列表(handlerMappings,在onRefresh中初始化),返回第一个调用getHandler
不为空的对象,得到HandlerExecutionChain对象。
而HandlerMapping对象的getHandler方法传入HttpservletRequest参数,意味着HandlerMapping可以根据request
的任意信息来决定生成HandlerExecutionChain的策略,如请求头,url路径,cookie,session(最常用还是url路径)
这意味着,我们可以自己编写HandlerMapping实现类,自定义根据request的哪个信息来生成HandlerExecutionChain。
HandlerExecutionChain主要由
private final Object handler;
private HandlerInterceptor[] interceptors;
组成,
其中handler代表HandlerAdapter实际执行的处理对象,它被定义成Object的意义在于你可以将java中的任意对象定义成
Handler来执行,返回最后的视图。
而handler执行前后,HandlerInterceptor列表将被依次执行,它可以看做是最handler执行方法的环绕通知,用于对handler
执行方法进行方便的处理和扩展,拦截器一般是自定义的。
2.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
遍历之前初始化的HandlerAdapter列表(handlerAdapters),返回第一个supports方法为true的对象,
得到HandlerAdapter对象。
我们也可以通过自定义的HandlerAdapter来执行handler对象。
3.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
HandlerAdapter对象调用handle方法,返回ModelAndview对象。
ModelAndview是springmvc中视图和模型数据的聚合,而视图则抽象成View接口了。
View接口定义了一个render方法用于渲染视图。其实现类包含在HandlerAdapter对象执行handle方法的返回值
中(ModelAndview),而返回的ModelAndview到View有一个视图解析的过程,所以返回的ModelAndview即可以
包含真正的视图View,也可以仅仅包含视图名,springmvc的视图解析器负责将视图名转成真正的视图对象。
至此,springmvc的请求处理流程结束。