《看透springMVC源码》笔记之核心Servlet

整体结构介绍

《看透springMVC源码》笔记之核心Servlet

在Servlet的继承结构中一共有5个类,GenericServlet和HttpServlet在java中,剩下三个类HttpServletBean、FrameworkServlet和DispatcherServlet是SpringMVC中的。
后边三个类直接实现三个接口:EnvironmentCapable、EnvironmentAware和ApplicationContextAware。XXXAware在spring里表示对XXX可以感知,通俗点讲就是:如果在某个类里面想要使用spring的一些东西,就可以通过实现XXXWare接口告诉spring,spring看到就会给你送过来,而接收的方式是通过实现接口唯一的方法set-XXX。EnvironmentCapable,顾名思义,就是具有Environment的能力,也就是可以提供Environment,所以EnvironmentCapable唯一的方法是Environment getEnvironment(),用于实现EnvironmentCapable接口的类,就是告诉spring它可以提供Environment,当spring需要Environment的时候就会跟它要。

HttpServletBean

初始化

在HttpServletBean的init中,首先将Servlet中配置的参数使用BeanWrapper设置到DispatcherServlet的相关属性,然后调用模板方法initServletBean,子类就通过这个方法初始化。

使用

HttpServlet主要参与了创建工作,并没有涉及请求的处理。

FrameworkServlet

初始化

入口方法是initServletBean,核心代码:

《看透springMVC源码》笔记之核心Servlet

核心代码只有两句话:一句话用于初始化WebApplicationContext,另一句用于初始化FrameworkServlet,而且initFrameworkServlet方法是模板方法,子类可以覆盖然后在里面做一些初始化的工作,但子类并没有使用它。可见FrameworkServlet在构建的过程中的主要作用就是初始化了WebApplicationContext。而它的initWebApplicationContext方法主要做了三件事:
1. 获取spring的根容器rootContext。
2. 设置webApplicationContext并根据情况调用onRefresh方法。
3. 将webApplicationContext设置到ServletContext中。

使用

在FrameServlet中重写了service、doGet、doPost、doPut、doDelete、doOptions、doTrace方法(除了doHead的所有处理请求的方法)。在service方法中增加了对PATCH类型请求的处理,其他类型的请求直接交给了父类进行处理;doOptions和doTrace方法可以通过设置dispatchOptionsRequest和dispatchTraceRequest参数决定是自己处理还是交给父类处理(默认都是交给父类处理,doOptions会在父类的处理结果中增加PATCH类型);doGet、doPost、doPut、和doDelete都是自己处理。所有需要自己处理的请求都交给了processRequest方法进行统一处理。
service和doGe代码,别的需要自己处理的方法都和doGet类似:
《看透springMVC源码》笔记之核心Servlet

processRequest是FrameworkServlet类在处理请求中最核心的方法:
《看透springMVC源码》笔记之核心Servlet
《看透springMVC源码》笔记之核心Servlet

processRequest方法中的核心语句是doService(request, response),这是一个模板方法,在DispatcherServlet中具体实现。
除了异步请求和调用doService方法具体处理请求,processRequest自己主要做了两件事情:
1. 对LocaleContext和RequestAttributes的设置及恢复;
2. 处理完后发布了ServletRequestHandledEvent。

LocaleContext里面存放着Locale(也就是本地化信息,如zh-cn等),RequestAttributes是spring的一个接口,通过它可以get/set/removeAttribute,根据参数判断操作request还是session。下面是setAttribute代码:
《看透springMVC源码》笔记之核心Servlet

LocaleContextHolder,这是一个abstract类,不过里面的方法都是static的,可以直接调用,而且没有父类也没有子类!也就是说我们不能对它进行实例化,只能调用其定义的static方法。
《看透springMVC源码》笔记之核心Servlet
inheritableLocaleContextHolder可以被子线程继承。
RequestContextHolder也是一样的道理,里面封装了RequestAttributes,可以get/set/removeAttribute,而且因为实际封装的是ServletRequestAttributes,所以还可以getRequest,getResponse,getSession!

DispatcherServlet

初始化

《看透springMVC源码》笔记之核心Servlet

使用

DispatcherServlet里面执行处理的入口方法是doService,不过doService没有直接进行处理,而是交给了doDispatch进行具体的处理,在doDispatch处理前做个快照备份,等doDispatch处理完之后(如果不是异步且未完成)进行还原,在做完快照后又对request设置做了一些属性:
《看透springMVC源码》笔记之核心Servlet
《看透springMVC源码》笔记之核心Servlet
《看透springMVC源码》笔记之核心Servlet

前四个属性webApplicationContext、localeResolver、themeResolver和themeSource在之后介绍的handler和view中需要使用,后面三个属性都和flashMap相关主要用于Redirect转发时参数的传递。redirect本身是没有传递参数的功能的,按普通的模式如果想传递参数,就只能将其写入url中,但是url长度有限,涉及敏感数据还不安全,这时就可以用flashMap来进行传递。

《看透springMVC源码》笔记之核心Servlet
当用户提交http://xxx/submit 请求后浏览器地址会自动跳转到http://xxx/showorders?Local=zh-cn 链接,而前两个属性(一般使用第二种设置),对客户是透明的,客户并不知道。

doDispatch中最核心的代码只要4句:
1. 根据request找到Handler;
2. 根据Handler找到对应的HandlerAdapter;
3. 用HandlerAdapter处理Handler;
4. 调用processDispatchResult方法处理上面处理之后的结果(包含找到View并渲染输出给用户)
《看透springMVC源码》笔记之核心Servlet
详细流程:
《看透springMVC源码》笔记之核心Servlet
《看透springMVC源码》笔记之核心Servlet

小结

主要分析了Spring MVC自身的创建过程,SpringMVC中Servlet一共有三个层次,分别是HttpServletBean、FrameworkServlet和DispatcherServlet。HttpServletBean直接继承自java的HttpServlet,其作用是将Servlet中配置的参数设置到相应的属性,没有涉及请求的处理;FrameworkServlet初始化了WebApplicationContext,相对Servlet重写了service,doGet等方法,核心方法是processRequest;DispatcherServlet初始化了自身的9个组件,核心doService,doDispatch。