Spring Web http request請求流程:
首先介紹這邊你需要知道的繼承體系,DispacherServlet繼承自FrameworkServlet,FrameworkServlet繼承自HttpServletBean,HttpServletBean繼承自HttpServlet,HttpServlet繼承自GenericServlet,GenericServlet實現Servlet、ServletConfig接口,我們的流程從請求進入到GenericServlet的service方法開始說起。
- 攔截器是在DispacherServlet的doDispatch方法中執行的,(url攔截器和用戶自定義的其他業務攔截器)
流程總覽:
容器監聽端口,接收到請求后調用Servlet的service方法,
在service方法中判斷用戶使用的是get還是post請求,決定后續調用對應的doGet/doPost方法,
在doGet/doPost方法中執行processRequest方法,
processRequest方法執行請求上下文的初始化過程,
然后調用doService()方法,
由該doService方法執行doDispatch方法,
最后由doDispatch方法去獲取請求的mappedHandler和HandlerAdapter,處理完用戶請求之后通過新建一個ServletWebRequest來渲染返回數據
首先調用GenericServlet的service()方法,源碼如下:
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
事實上GenericServlet的service()方法是一個抽象方法,而HttpServlet繼承了GenericServlet,所以此處實際調用了HttpServlet的service方法,HttpServlet的service方法源碼如下:
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
this.service(request, response);
} else {
throw new ServletException("non-HTTP request or response");
}
}
首先判斷ServletRequest、ServletResponse是否是標准的HttpServletRequest、HttpServletResponse,如果不是則拋出ServletException異常,否則繼續調用實現類的service()方法
對源碼做debug我們知道,this.service(request, response);執行到spring FrameworkServlet的service方法。
在spring框架中,FrameworkServlet繼承自HttpServletBean,HttpServletBean是一個抽象類,HttpServletBean繼承自HttpServlet。
所以HttpServlet的service方法中調用的this.service(request, response);其實是執行的是FrameworkServlet中的service方法。繼續看源碼:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod != HttpMethod.PATCH && httpMethod != null) {
super.service(request, response);
} else {
this.processRequest(request, response);
}
}
我們的HttpMethod 應該是POST或者GET方法,所以執行super.service(request, response);回到HttpServlet的service(HttpServletRequest req, HttpServletResponse resp)方法:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if (ifModifiedSince < lastModified) {
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);
}
}
我們一GET請求為例,直接看this.doGet(req, resp);回到FrameworkServlet的doGet方法:
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processRequest(request, response);
}
執行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);//此處調用其實現類的buildLocaleContext方法,spring中即DispatcherServlet,來創建localeContext 對象
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
//注冊攔截器registerCallableInterceptor
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor());
//初始化應用context
this.initContextHolders(request, localeContext, requestAttributes);
try {
this.doService(request, response);
} catch (ServletException var17) {
failureCause = var17;
throw var17;
} catch (IOException var18) {
failureCause = var18;
throw var18;
} catch (Throwable var19) {
failureCause = var19;
throw new NestedServletException("Request processing failed", var19);
} finally {
this.resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
if (this.logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", (Throwable)failureCause);
} else if (asyncManager.isConcurrentHandlingStarted()) {
this.logger.debug("Leaving response open for concurrent processing");
} else {
this.logger.debug("Successfully completed request");
}
}
this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
}
}
可以看到,在FrameworkServlet的processRequest方法中執行了一系列的初始化操作,然后調用this.doService(request, response);也就是調用DispatcherServlet的doService方法
來看DispatcherServlet的doService方法的源碼:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
//省略掉一些request屬性的代碼
try {
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
該方法中主要完成一些request的屬性設置,然后this.doDispatch(request, response);源碼如下:
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 {
//處理multipart 請求
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
//從容器中獲取mappedHandler
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
// 從容器中獲取適配器HandlerAdapter 。這個過程中,會調用MappedInterceptor的matches方法,以此來判斷次url是否在攔截范圍內
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
//處理get請求
if (isGet || "HEAD".equals(method)) {
//lastModified最后修改時間 此處返回-1
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (this.logger.isDebugEnabled()) {
this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
// 檢查請求是否使用緩存
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
//執行攔截器中的preHandle攔截方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//執行用戶controller中對應的業務
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//渲染默認的mv
this.applyDefaultViewName(processedRequest, mv);
//執行PostHandle攔截方法
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);
}
}
}