一般用户从浏览器发出的请求会先到我们的web服务器(如:Nginx、Apache等),然后转发至应用服务器(如:Tomcat等),而Tomcat是Servlet容器,掌握着Servlet的生命周期,它接收、处理遵循Servlet规范的请求并返回结果,Tomcat的功能可以简单理解成将浏览器的请求封装成javax.servlet.http.HttpServletRequest和javax.servlet.http.HttpServletResponse两个对象传送给我们用JAVA编写的应用程序。所以我们可以断定我们的程序是能够处理Servlet请求,那么我们带着验证这个问题去阅读SpringMVC的源码,看SpringMVC框架是怎样帮助我们的程序做到完美处理Servlet请求的。
回忆刚工作接触的Spring项目时,在我们的工程里的web.xml中总是有这样的配置
springServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring-mvc.xml
0
springServlet
/
后来了解到这样的配置使得在我们的应用容器或者说Servlet容器启动的时候便启动org.springframework.web.servlet.DispatcherServlet这个Servlet。而这个Servlet就是用来处理用户请求的。
首先我们来看一下DispatcherServlet的类图
从类图中我们可以看出DispatcherServlet最终实现了Servlet的中所有的方法。
现在我们可以通过查看源码去查看相关的调用链路。
现在假如我们在浏览器通过Get方式请求这个接口
首先会到达HttpServlet的service方法。方法代码如下:
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
该方法以及以后的源码中的其他方法中的细节暂时都忽略,以了解主要逻辑为当前阶段的目的。
在service
方法中会调用doGet(req, resp);
方法,查看通过DispatcherServlet类去调用的doGet(req, resp);
方法是调用的org.springframework.web.servlet.FrameworkServlet#doGet
的方法,代码如下:
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.processRequest(request, response);
}
再查看org.springframework.web.servlet.FrameworkServlet#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);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor(null));
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();
}
this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
}
}
继续查看查看通过DispatcherServlet
对象去调用的doService
方法是org.springframework.web.servlet.DispatcherServlet#doService
主要代码如下:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
//省略暂时不用关心的代码
try {
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
继续查看通过DispatcherServlet
对象调用的doDispatch
方法org.springframework.web.servlet.DispatcherServlet#doDispatch
org.springframework.web.servlet.DispatcherServlet#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 {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
//检查、处理二进制数据请求
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
//获取Handler
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
//获取HandlerAdapter
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
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;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//处理请求,获得mv
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
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);
}
}
}
刚开始我们可能无法理解Spring中为什么代码逻辑要这样编写的原因,所以理解起来比较困难,看得云里雾里的。
以上调用链路用下面的图总结一下,便于加深影响。(第一次画时序图,感觉不太对)
现在会过头看看SpringMVC为什么要通过getHandler
去拿到一个HandlerExecutionChain
,这个的内部结构如下
在一定程度上我们可以把Handler理解成就是我们的业务处理器(Controller)。拿到Handler之后需要通过getHandlerAdapter
去找到能处理该类型Handler
的Adapter。
以上我们分析的Spring处理请求的链路是基于XML配置的源码解析。如果你是通过注解(Annotation)的方式去配置的Bean,那么Spring的处理方式流程还是一样,里面的实际处理getHandler
,getHandlerAdapter
对象会有不同,所以Spring是灵活可扩展的框架,以后版本如果有其他的方式去配置Spring也很方便。getHandler
,getHandlerAdapter
内部的处理逻辑的模式保证了SpringMVC框架的高度可扩展性。
springframework4.3.0.RELEASE版本中org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping已经标注过时(@Deprecated),所以无论哪种配置方式getHandler的实际处理对象都是org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
通过注解(Annotation)方式getHandlerAdapter的实际处理对象是
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter