题记:
为了解SpringMVC加载过程的细节,最近阅读了其部分源码,并自己手写实现了一个简单的SpringMVC框架,现记录作为总结。
分为三篇博客:
• 源码分析之Spring MVC上下文的加载细节(一)
• 源码分析之Spring MVC上下文的加载细节(二)【本篇】
• 源码分析之动手实现手写一个自己的SpringMVC框架(三)
阅读完这三篇博客,将了解到:
• Spring容器整套技术是如何与我们web容器的耦合?
• Spring MVC启动自己持有的MVC上下文之前需要IOC容器的支持,Spring是如何驱动IOC容器的初始化的细节的?
• Spring MVC上下文初始化以及组件和服务初始化细节?
• 完成一个属于的自己SpringMVC框架
1.Spring MVC上下文初始化
首先看下图:
这个继承体系说明,Servlet容器(如Tomcat)可以读取到SpringMVC运行的整个过程(init -> service -> destroy)。
当Request请求来的时候,先到Servlet容器环境,通过继承关系将Request请求传入到SpringMVC中处理。
传入之前,SpringMVC要先初始化,现在我们来阅读源码(注意代码注释),了解SpringMVC上下文的初始化(init)。
第一步:HttpServletBean是对接Servlet容器接收传入参数的类,我们首先查看HttpServletBean中init方法:
这样做的最终目的是初始化各个Bean组件信息。而需要初始化Bean组件信息前提需要宿主环境,于是进入第二步。
第二步:查看模板方法initServletBean,也就来到了FrameworkServlet类中初始化SpringMVC自己持有的上下文:
继续查看initWebApplicationContext方法的实现:
基本完成SpringMVC上下文环境(WebApplicationContext)的初始化:
第三步:查看onRefresh方法,来到DispatcherServlet类中:
小结:
2.SpringMVC服务执行流程细节
注意了,这个是理解SpringMVC的重点内容,手写自己的SpringMVC框架就是模仿简化这个流程来的。
查看DispatcherServlet的doService方法源码:
接着查看doDispatch源码,深入理解service的处理:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1.用户请求
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.
// 2.根据Request查询找到handler,3.并返回处理器执行链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 4.请求执行handler,根据handler找到HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
// 处理Get、Head请求的Last-Modified
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
// 是否使用缓存页面
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的preHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 5.HandlerAdapter执行Handler处理请求(6.返回ModelAndView),
// 7.返回ModelAndView到DispatcherServlet
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 如果需要异步处理直接返回
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 当mv的view为空时,根据request设置默认view
applyDefaultViewName(request, mv);
// 执行相应的Interceptor的preHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
// 8、9、10.处理返回结果。(包括处理异常,渲染页面,发出完成通知触发Interceptor的afterCompletion)
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
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
// 删除上传请求的资源
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
小结(记住这张图!!!):
完毕,下一篇文章:源码分析之动手实现手写一个自己的SpringMVC框架(三)