上一篇博文SpringMVC源碼分析(一) 中已經對SpringMVC中的Servlet(GenericServlet,HttpServlet,HttpServletBean,FrameworkServlet,DispatcherServlet)源碼進行分析,今天接着分析SpringMVC請求處理過程。
SpringMVC請求處理過程主要由DispatchServlet來負責完成,FrameworkServlet是DispatchServlet的父類,先看一下FrameWorkServlet的處理請求過程。
當接收到請求時會調用service方法,代碼如下:
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
processRequest(request, response);//如果請求方式是PATCH時直接調用
}
else {
super.service(request, response);//調用父類的service方法,也就是HttpServlet的service方法
}
}
service方法中會根據請求類型選擇處理方式,比如get請求就會調用doGet()方法,
FrameworkServlet中重寫doGet()方法,代碼如下:
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
所以最後會調用processRequest處理請求,processRequest是FrameworkServlet類處理請求的核心方法。
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
//獲取LocalContextHolder中保存LocalContext(保存了本地化信息,比如zh-cn)
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
//獲取當前請求的LocalContext(保存了本地化信息,比如zh-cn)
LocaleContext localeContext = buildLocaleContext(request);
//獲取RequestContextHolder保存的RequestAttributes
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
//獲取當前請求的RequestAttributes
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
//將當前的LocalContext和RequestAttributes分別放置到LocalContextHolder和RequestContextHolder中
initContextHolders(request, localeContext, requestAttributes);
try {
//實際處理請求的入口
doService(request, response);//在DispatchServlet中實現
}
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 {
//恢復原來的LocalContext和ServletRequestAttributes到LocalContextHolder和RequestContextHolder中
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();//執行完這個方法後isRequestActive()返回值爲false
}
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");
}
}
}
//發送servletRequestHandlerEvent消息
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
ServletRequestAttributes中封裝了我們平時使用setAttribute和getAttribute方法,根據scope參數來判斷是request還是session。
@Override
public void setAttribute(String name, Object value, int scope) {
if (scope == SCOPE_REQUEST) {
if (!isRequestActive()) {//上面調用了requestCompleted之後就會變爲false也就是不進行操作了
throw new IllegalStateException(
"Cannot set request attribute - request is not active anymore!");
}
this.request.setAttribute(name, value);
}
else {
HttpSession session = getSession(true);
this.sessionAttributesToUpdate.remove(name);
session.setAttribute(name, value);
}
}
publishRequestHandledEvent方法是請求處理結束後會發出消息,無論請求是否成功都會發出。
接下來繼續看service()處理請求,service方法會調用doService方法,doService是個模板方法,DispatcherServlet中重寫了這個方法,我們轉到ServletDispatcherServlet上分析處理請求過程,DispatcherServlet是Spring 的最核心的類。整個處理請求的過程的頂層設計都在這裏。我們來看看DispatcherServlet的doService方法。
@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.
Map<String, Object> attributesSnapshot = null;
//當include請求時把request中的atrribute備份一份
if (WebUtils.isIncludeRequest(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.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());//設置webApplication
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);//設置localResolver
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);//設置themeResolver
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());//設置themeResource
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);//用於redirect中attribute的數據傳遞
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()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
//還原request中的attribute
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
繼續追蹤doDispatch方法,doDispatch主要的任務是根據request找到Handler,根據handler找到相對應的HandlerAdapter,用HandlerAdapter處理Handler,最後把結果通過processDispatchResult()返回,實現代碼如下:
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);//通過請求找到handler(這裏的handler就是我們說的Controller中處理請求的方法)
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);//沒有找到handler則調用此方法處理
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//通過handler找到HandlerAdapter
// Process last-modified header, if supported by the handler.
String method = request.getMethod();//獲取請求方式
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
//處理GET、HEAD請求的Last-Modified
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;
}
}
//執行相應Interceptor的preHandler方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//handlerAdapter使用handler處理請求
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//當View爲空時,比如我們寫的Controller中處理請求的方法爲空時,根據request的設置view
applyDefaultViewName(processedRequest, mv);
//執行相應Intercerptor的postHandler方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//返回處理結果,包括異常處理、渲染頁面、發出通知出發Interceptor的afterCompletion方法
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()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request. //如果是上傳請求刪除請求的資源
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
可以看出doDispatch方法中的核心工作就是
1.根據當前Request找到handler;
2.根據Handler找到對應的HandlerAdapter;
3.使用HandlerAdapter處理handler
4.調用processDispatchResult方法處理上面請求之後的結果
補充幾個重要的概念:
Handler:也就是處理器,他直接對應着MVC的Controller層,他的表現形式很多,標註了@RequestMapping的所有方法都可以看出一個handler,只要能處理實際請求的就可以是Handler。
HandlerMapping:用來查找Handler的,SpringMVC的請求很多,每個請求都需要一個handler來處理,收到的請求由那個handler來處理就由HandlerMapping來確定。
HandlerAdapter:他就是一個適配器,SpringMVC中handler的形式可以任意,主要能處理請求就OK,但是Servlet處理請求的方法結構是固定的。如何讓固定的servlet處理方法調用靈活的handler來處理就由HandlerAdapter來實現。
接着分析handlerAdpter中調用handler方法處理請求。
public interface HandlerAdapter {
//判斷是否可以用某個handler
boolean supports(Object handler);
//具體使用Handler處理請求
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
//返回LastModified的值
long getLastModified(HttpServletRequest request, Object handler);
}
我們只要實現HandlerAdapter接口就可以處理請求,SimpleControllerHandlerAdapter實現了HandlerAdapter,實現代碼如下:
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
//判斷是否可以用某個handler
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//調用Controller接口中的handleRequest方法,我們如果繼承了Controller接口就需要重寫這個方法,然後在裏面處理邏輯即可。
return ((Controller) handler).handleRequest(request, response);
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
請求處理完的結果會封裝在ModelAndView中,我們通過processDispatchResult方法把結果渲染到頁面中,實現代碼如下:
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, 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?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);//調用此方法進行頁面渲染
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
//發出請求處理完成的通知,出發Interceptor的afterCompletion
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
在render方法中會去查找視圖解析器,然後轉化成View類型的視圖(比如jsp,html,freemaker等)顯示在頁面上。