Spring WebMVC
Spring 接受前端请求的处理过程,根据 SpringBoot 2.4.2 版本。
doService
放入各种属性到 request
对象上,然后交给 doDispatch
进行代理转发:
public class DispatcherServlet extends FrameworkServlet {
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
// ...
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
// ...
doDispatch(request, response);
}
}
doDispatcher
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 用哪个 Handler 链处理请求
mappedHandler = getHandler(processedRequest);
// 用哪个 Handler adapter 处理请求
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 处理 last-modified 头
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 请求拦截器
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 开始实际处理请求
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 请求拦截器
mappedHandler.applyPostHandle(processedRequest, response, mv);
// 处理请求的结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
}
getHandler
// DispatcherServlet.java
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
handlerMappings
有哪些:
找到最匹配的 HandlerExecutionChain
以后,这个类内部的 handler
指向的就是 XXXController
这个类。
getHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
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");
}
handlerAdapters
有哪些:
处理 Last-Modified
如果是 GET
或者 HEAD
请求,检查是否是携带了 last-modified
头:
// ServletWebRequest.java
public boolean checkNotModified(@Nullable String etag, long lastModifiedTimestamp) {
HttpServletResponse response = this.getResponse();
if (!this.notModified && (response == null || HttpStatus.OK.value() == response.getStatus())) {
if (this.validateIfUnmodifiedSince(lastModifiedTimestamp)) {
if (this.notModified && response != null) {
response.setStatus(HttpStatus.PRECONDITION_FAILED.value());
}
return this.notModified;
} else {
boolean validated = this.validateIfNoneMatch(etag);
if (!validated) {
this.validateIfModifiedSince(lastModifiedTimestamp);
}
if (response != null) {
boolean isHttpGetOrHead = SAFE_METHODS.contains(this.getRequest().getMethod());
if (this.notModified) {
response.setStatus(isHttpGetOrHead ? HttpStatus.NOT_MODIFIED.value() : HttpStatus.PRECONDITION_FAILED.value());
}
if (isHttpGetOrHead) {
if (lastModifiedTimestamp > 0L && this.parseDateValue(response.getHeader("Last-Modified")) == -1L) {
response.setDateHeader("Last-Modified", lastModifiedTimestamp);
}
if (StringUtils.hasLength(etag) && response.getHeader("ETag") == null) {
response.setHeader("ETag", this.padEtagIfNecessary(etag));
}
}
}
return this.notModified;
}
} else {
return this.notModified;
}
}
检查 Last-Modified
的处理过程如下:
(1) 自上次某个修改时间以来是否没有变化过
查看 If-Unmodified-Since
头:
private boolean validateIfUnmodifiedSince(long lastModifiedTimestamp) {
if (lastModifiedTimestamp < 0L) {
return false;
} else {
long ifUnmodifiedSince = this.parseDateHeader("If-Unmodified-Since");
if (ifUnmodifiedSince == -1L) {
return false;
} else {
this.notModified = ifUnmodifiedSince < lastModifiedTimestamp / 1000L * 1000L;
return true;
}
}
}
(2) 是否 Non-Match
上述如果不匹配,那么就会检查 etag
和 If-None-Match
是否匹配:
private boolean validateIfNoneMatch(@Nullable String etag) {
if (!StringUtils.hasLength(etag)) {
return false;
} else {
Enumeration ifNoneMatch;
try {
ifNoneMatch = this.getRequest().getHeaders("If-None-Match");
} catch (IllegalArgumentException var5) {
return false;
}
if (!ifNoneMatch.hasMoreElements()) {
return false;
} else {
etag = this.padEtagIfNecessary(etag);
if (etag.startsWith("W/")) {
etag = etag.substring(2);
}
while(true) {
while(ifNoneMatch.hasMoreElements()) {
String clientETags = (String)ifNoneMatch.nextElement();
Matcher etagMatcher = ETAG_HEADER_VALUE_PATTERN.matcher(clientETags);
while(etagMatcher.find()) {
if (StringUtils.hasLength(etagMatcher.group()) && etag.equals(etagMatcher.group(3))) {
this.notModified = true;
break;
}
}
}
return true;
}
}
}
}
(3) 是否自某个时间开始后修改了
private boolean validateIfModifiedSince(long lastModifiedTimestamp) {
if (lastModifiedTimestamp < 0L) {
return false;
} else {
long ifModifiedSince = this.parseDateHeader("If-Modified-Since");
if (ifModifiedSince == -1L) {
return false;
} else {
this.notModified = ifModifiedSince >= lastModifiedTimestamp / 1000L * 1000L;
return true;
}
}
}
请求拦截器
请求拦截器在真正处理请求前进行拦截器的 preHandle
和 postHandle
处理:
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i < this.interceptorList.size(); i++) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
return true;
}
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}
处理结果
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
if (exception != null) {
}
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
}
}
render
会渲染 ModelAndView
:
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
String viewName = mv.getViewName();
View view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
view.render(mv.getModelInternal(), request, response);
}