Spring MVC源码解析
在讲解springmvc之前,其实是需要大家了解一点tomcat的源码知识的,但是大部分的初学者还只停留在应用的层面,所以,下面展示tomcat容器初始化的流程图和加载servlet的流程图,大家只需要先记住他们的执行顺序即可,等后续开始tomcat源码之后我们再做下一步深入了解。
1、Tomcat容器初始化流程图
![img](Spring MVC源码解析/tomcat容器初始化流程图.png)
2、tomcat加载servlet流程图
![img](Spring MVC源码解析/加载servlet流程图.png)
从上述流程开始看起,我们发现最终会调用Servlet的init方法,SpringMVC中最核心的类就是DispatcherServlet,因此需要找到init方法。
1、DispatcherServlet的初始化
DispatcherServlet的类图:
![image-20200314005616939](Spring MVC源码解析/DispatcherServlet类图.png)
可以看到,DispatcherServlet继承自HttpServlet,它的本质就是一个Servlet,但是此类中并没有init方法,因此要去父类中进行查找,最终在HttpServletBean类中重写了父类GenericServlet的init方法。因此当tomcat容器启动的时候会调用init方法开始执行,中间会经历N多个环节,此处不需要了解,唯一需要注意的一个点,就在于SpringMVC的组件会调用DispatcherServlet的组件进行初始化工作,这些初始化工作会完成对于九大组件的初始化,这个初始化会从DispatcherServlet.properties文件中进行相应的属性值加载。
HttpServletBean———init()
1 | public final void init() throws ServletException { |
调用子类方法实现初始化BeanServlet
FrameworlServlet——initServletBean
1 | protected final void initServletBean() throws ServletException { |
此后的流程会进入到Spring的onRefresh方法中,最终会调用DispatcherServlet中的onRefresh方法。
1 |
|
这几个组件的初始化过程都差不多,因此我们选择一个来重点描述,其他的需要大家下去之后自己来研究了。
1 | private void initHandlerMappings(ApplicationContext context) { |
通过默认策略来加载默认的配置项
1 | protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) { |
默认策略就完成了从DispatcherServlet.properties文件中加载的属性值
1 | private static final Properties defaultStrategies; |
以上的操作就是DispatcherServlet的组件的初始化过程,下去之后一定要把每个过程详细看一下,如果能够结合spring进行查看就更好了。
2、DispatcherServlet的请求处理
我们都知道当发送请求的时候每次都是找到Servlet的doget或者dopost方法中,但是你在DispatcherServlet中并没有看到这两个方法,还是按照老规矩,子类没有去父类找实现。
FrameworkServlet.java
1 |
|
大家看到无论发送什么请求,最终都会进入到processRequest方法中,此方法用来处理我们从浏览器发送的请求,
1 | protected final void processRequest(HttpServletRequest request, HttpServletResponse response) |
大家看到了,在上述方法中,实际调用的是子类的doService方法,也就是DispatcherServlet中的方法实现,现在终于回归到我们要重点关注的类了,接着向下看;
DispatcherServlet doService
1 |
|
到此为止,就该执行DispatcherServlet的核心方法doDispatcher,此方法完成了我们需要的全部功能,接着向下看。
3、DispatcherServlet的核心处理方法doDispatcher
1 | protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { |
如果把刚刚的大致流程都搞清楚的话,那么我们下面开始分析每一个环节的具体流程,下面的代码会比较多,大家尽力去理解。
3、上传组件的请求处理
processedRequest = checkMultipart(request);
1 | protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException { |
4、获取请求处理器
mappedHandler = getHandler(processedRequest);
1 | protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { |
在springmvc中默认会加载三个请求处理类:RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping。这几个类都是在初始化的时候设置成功的,同样的,他们也具备相同的父类AbstractHandlerMapping,无论哪一个处理类最终都会嗲用getHandler方法,此方法在父类中,没有在子类中实现,下面来看这个方法的逻辑:
AbstractHandlerMapping getHandler()
1 | public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { |
5、获取请求处理类的适配器类
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
1 | protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { |
此适配器集合共有三个具体实现子类,分别是:HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter,然后根据support方法来判断使用哪种适配器,并将对应的适配器对象返回。
6、执行前置拦截器链
if (!mappedHandler.applyPreHandle(processedRequest, response))
1 | boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { |
7、根据适配器类去处理对应的请求,并返回ModelAndView对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
1 | public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) |
7、设置默认的视图名称
applyDefaultViewName(processedRequest, mv);
1 | /** |
8、执行后置拦截器链
mappedHandler.applyPostHandle(processedRequest, response, mv);
1 | void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) |
9、处理Controller返回的结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
1 | private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, |
在上述的处理过程中,有两个比较重要的方法,第一个是发生异常时,把异常处理为mv返回值的逻辑processHandlerException,第二个是对返回的mv结果进行渲染的逻辑render。
10、处理器异常处理方法
mv = processHandlerException(request, response, handler, exception);
1 |
|
11、视图渲染方法:
render(mv, request, response);
1 | protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { |
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
1 |
|