#SpringMVC源码分析
SpringMVC 默认有一个 DispatcherServlet
映射所有的请求("/"),然后进行分发(dispatch)处理:
<!-- SpringMVC 默认的 DispatcherServlet -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
除非用户在 web.xml
中,自定义 Servlet
映射 **指定路径的请求 **处理,否则所有的请求都会进入DispatcherServlet
处理:
<!-- 用户自定义的Servlet -->
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>com.yunding.MyServelt</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/myServlet</url-pattern>
</servlet-mapping>
DispatcherServlet类的继承关系
[外链图片转存失败(img-pB4barTI-1563614868603)(C:\Users\ADMINI~1\AppData\Local\Temp\1561441818709.png)]
DispatcherServlet
类 间接地父类实现了 Servlet
接口,因此其本质上依旧是一个Servlet
/** * Servlet接口定义了 带参数的init(ServletConfig config)方法 */
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
void service(ServletRequest var1, ServletResponse var2);
。。。
}
/** * GenericServlet抽象类 */
public abstract class GenericServlet implements Servlet {
/** * 重写了Servlet接口的带参的init(ServletConfig config)方法 * 这里有两步操作: 1.加载servletConfig 2.调用自己声明的无参的init()方法 * 但是没有编写init()的具体代码,这么做的目的: * 如果Servlet业务逻辑部分的开发者继承了GenericServelt, * 那么GenericServelt类的带参的init(ServletConfig config)方***帮开发者加载servletConfig, * 于是开发者只需要专心编写业务逻辑而不用关心ServletConfig相关的部分 * 如果开发者需要在Servlet的init阶段进行一些操作的话,可以自己去重写无参的init()方法 */
public void init(ServletConfig config) throws ServletException {
// 加载配置
this.config = config;
// 在这里调用了无参的init()方法
this.init();
}
// GenericServlet声明的 无参的init()方法(内容是空的!)
public void init() throws ServletException {
}
}
HttpServlet
类 主要是重写了 Servlet
接口的service()
方法(可参考 JavaServlet 3.0规范 请求处理方法),
(有关 Servlet生命周期 的知识也可以参考 JavaServlet 3.0 规范 )
/** * HttpServlet没有去实现 GenericServlet 类中无参的init()方法,所以, * 如果你的类继承了HttpServlet, * 那么重写他的无参init()方法 其实就是在重写GenericServlet的无参init()方法, * 因为HttpServlet没有改变过无参的init() */
public abstract class HttpServlet extends GenericServlet {
...
}
HttpServlet
是 javax.servlet.http
包下的类
HttpServletBean
、FrameworkServlet
、DispatcherServlet
是 org.springframework.web.servlet
包下的类
很明显,HttpServlet
和 Spring 是用 HttpServletBean
的形式来连接的,
或者说, **Spring **通过把 HttpServlet
包装成 HttpServletBean
来方便自己进一步操作
/** * HttpServletBean抽象类 */
public abstract class HttpServletBean extends HttpServlet {
/** * 如上所说,为了在Servlet初始化阶段做一些事情, * HttpServletBean重写了GenericServlet声明的无参的init()方法 */
public final void init() throws ServletException {
if (!pvs.isEmpty()) {
// 把当前对象包装成一个BeanWrapper
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
。。。
}
// 调用了 initServletBean()方法
this.initServletBean();
}
/** * 声明了一个protected修饰的 initServletBean()方法(没有实现) * 老规矩:用于提供给子类重写 */
protected void initServletBean() throws ServletException {
}
}
/** * FrameworkServlet抽象类 */
public abstract class FrameworkServlet extends HttpServletBean {
/** * initServletBean()的实现来啦。。。 */
protected final void initServletBean() throws ServletException {
long startTime = System.currentTimeMillis();
this.webApplicationContext = this.initWebApplicationContext();
this.initFrameworkServlet();
// 打印日志
if (this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + this.getServletName() +
"': initialization completed in " + elapsedTime + " ms");
}
}
}
FrameworkServlet
打印的日志在这里,似曾相识否 :
[外链图片转存失败(img-hN1VuIjB-1563614868604)(C:\Users\ADMINI~1\AppData\Local\Temp\1561447040159.png)]
/** * DispatcherServlet类 * DispatcherServlet调用到的方法简单梳理 */
public class DispatcherServlet extends FrameworkServlet {
/** * 从HttpServlet继承的 public 修饰的 service()方法,这个方法是我自己补出来的 * 源码并没有显式地写出来,它本身在HttpServlet中,但是父类的就是子类的,所以没什么毛病 */
public void service(ServletRequest req, ServletResponse res) {
// 调用下面的 protected修饰的 service()方法
this.service(request, response);
}
/** * 从FrameworkServlet继承的 protected 修饰的 service()方法 */
protected void service(HttpServletRequest request, HttpServletResponse response) {
// 调用父类的service()方法,其实就是HttpServlet的protected servicce()方法
super.service(request, response);
}
/** * 这就是上面的super.service()方法,当然,他已经被上面的protected service()方法重写了 * 这里写出来是不正确的,只是为了展示方法的调用流程 */
protected void service(HttpServletRequest req, HttpServletResponse resp) {
String method = req.getMethod();
if (method.equals("GET")) {
// 在protected HttpServlet.service()中调用了this.doGet()方法
this.doGet(req, resp);
}
。。。
}
/** * FrameworkServlet类的doGet()方法 * 虽然是在HttpServlet类中调用的this.doGet()方法,但是真正被调用的不是HttpServlet的doGet方法 * 而是子类FrameworkServlet中的doGet()方法,因为在这条调用流程中, * HttpServlet.service()中的this指针代表的是子类(FrameworkServlet)对象,原因在此代码块结束写 */
protected final void doGet(HttpServletRequest request, HttpServletResponse response) {
// 在FrameworkServlet中不管是GET还是POST或者其他的方法全部统一到processRequest中处理
this.processRequest(request, response);
}
/** * processRequest方法 */
protected final void processRequest(HttpServletRequest request,
HttpServletResponse response) {
// 调用doService()方法
this.doService(request, response);
}
/** * 重写了FrameworkServlet中的doService()方法 */
protected void doService(HttpServletRequest request, HttpServletResponse response) {
// 调用doDispatch方法
this.doDispatch(request, response);
}
/** * 核心方法 doDispatch(request, response); * 里面清楚地展示了Interceptor的三个方法的运作时期及其作用原理 */
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
HttpServletRequest processedRequest = request;
HandlerExecutionChain handlerExecutionChain = null;
ModelAndView mv = null;
try {
/** * 根据request 获取HandlerExecutionChain */
handlerExecutionChain = this.getHandler(processedRequest);
/** * 执行所有 Interceptor的 preHandle(request, response, handler)方法 */
if (!handlerExecutionChain.applyPreHandle(processedRequest, response)) {
// 如果有preHandle的结果是 false,就不执行之后的步骤
return;
}
/** * 从handlerExecutionChain中获取Handler,并获取handler对应的适配器(Adapter) */
HandlerAdapter ha = this.getHandlerAdapter(handlerExecutionChain.getHandler());
/** * 用handler的适配器执行handler, 处理完成后得到 ModelAndView */
mv = ha.handle(processedRequest, response, handlerExecutionChain.getHandler());
/** * 执行所有 Interceptor的 postHandle(request, response, handler, modelAndView)方法 * 从这里可以看出interceptor中的postHandle()方法是在渲染视图之前调用的 */
handlerExecutionChain.applyPostHandle(processedRequest, response, mv);
/** * 处理 ModelAndView 对象: 渲染视图 */
this.processDispatchResult(processedRequest,
response,
mappedHandler,
mv,
(Exception)dispatchException);
} finally {
/** * 执行所有 Interceptor的 afterCompletion(request, response, handler, ex)方法 */
handlerExecutionChain.applyAfterConcurrentHandlingStarted(processedRequest,
response);
}
}
}
this.doGet() 为什么调用的是子类的doGet方法
以下是打的断点:
[外链图片转存失败(img-kzUPHKiT-1563614868606)(C:\Users\ADMINI~1\AppData\Local\Temp\1561509975052.png)]
[外链图片转存失败(img-2kaxkT4h-1563614868607)(C:\Users\ADMINI~1\AppData\Local\Temp\1561517372694.png)]
[外链图片转存失败(img-zwshc12v-1563614868608)(C:\Users\ADMINI~1\AppData\Local\Temp\1561517403644.png)]
[外链图片转存失败(img-SxgkemjM-1563614868609)(C:\Users\ADMINI~1\AppData\Local\Temp\1561517426585.png)]
[外链图片转存失败(img-FIVPa2wD-1563614868610)(C:\Users\ADMINI~1\AppData\Local\Temp\1561517447245.png)]
[外链图片转存失败(img-H4bqr1f7-1563614868612)(C:\Users\ADMINI~1\AppData\Local\Temp\1561517527059.png)]
[外链图片转存失败(img-zFqYObef-1563614868613)(C:\Users\ADMINI~1\AppData\Local\Temp\1561517565053.png)]
[外链图片转存失败(img-gsLXtuok-1563614868615)(C:\Users\ADMINI~1\AppData\Local\Temp\1561517587853.png)]
DispatcherServlet处理流程
第一次请求时需要初始化Servlet(init)
14868613)]
[外链图片转存中…(img-gsLXtuok-1563614868615)]
DispatcherServlet处理流程
第一次请求时需要初始化Servlet(init)