springMVC的核心源码分析和它的工作机制
springMVC是一个基于spring的web框架,也可以说是spring的一个子容器,我们来谈谈sringMVC
一、springMVC的请求处理流程
首先我们来一张很形象的简单的流程图
1、DispatherServlet顾名思义一个调度的Servlet,是一个front-controller(前端控制器),也可以说是springMVC的C位哈哈,负责接受客户端的request,并将这些request分配给对应的处理组件
2、HandlerMapping顾名思义映射处理器,是一个url和controller的映射组件,DispatcherServlet拦截request的请求然后对请求URL进行解析得到URI(资源标识符),接着根据该URI调用HandlerMapping获得Handler配置的所有相关对象(包括Handler对象以及Handler对象对应的拦截器)最后封装到HandlerExecutionChain对象中返回
3.DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法)
4.提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5.Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
6.根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
7.ViewResolver 结合Model和View,来渲染视图
8.将渲染结果返回给客户端。
接下来我们根据核心源码来分析它里面的结构
首先我们了解springMVC这个框架 它本身提供的这些默认的组件我们可以在DispatcherServlet.properties这个配置文件可以看到
接下俩我们可以看一下Dispatcher类的层次结构
我们直接把重点放在DispatcherServlet(front-controller)
从流程图可以看出,用户的请求最先到达就是DispatcherServlet,它是springmvc的核心,可以把它叫做中央处理器,因此我们分析源码之前,先看看他是什么样的流程,通过源码可以看出,它是继承FrameworkServlet,它也是springmvc提供的类,继续往下继承关系看,FrameworkServlet继承HttpServletBean,她是spring提供的类,最终直到到它继承HttpServlet
我们接着看这个关系图,它是不是实现了这个servlet接口,既然它是servlet,那么它肯定有一个service方法(servlet最核心的方法),我么看这个方法在哪里实现的,一个个看,发现HttpServletBean并没有,再看FrameworkServlet发现有了,因此spring实现这个serivice方法在这里实现的
这个方法的作用的就是得到客户端的请求,然后判断这个请求是不是PATCH请求方式,如果不是就调用父类(httpServlet)中的service方法,我们调用父类这个service方法其实实际是调用该类的
doget方法或者dopost方法等等,拿到不同的请求方式处理不同的业务,我们以get方式为例吧
拿到这个方法,我们进入到processRequest方法
以上其他代码我们不用细看,是一些关于控制器的代码,我们直接进入doservice方法
我们可以看到我们跳到DispatcherServlet这个类里面来了,其实doSerivice可以猜到被子类各种重写哈哈,话不多讲直接进入doDispatch这个方法
前面的那些都不是核心代码,我们进入到这个doDispatcher方法才算进入springmvc的核心代码区域,由源码可得:它首先主要创建一个ModelAndView对象 = null,首先判断当前请求是不是
二进制的请求processedRequest = this.checkMultipart(request),然后我们再看底下代码
mappedHandler = this.getHandler(processedRequest);就是根据当前请求去拿一个handler(控制器),这个handler其实就是我们的控制器包括我们处理业务逻辑的controller,进入到这个方法的源码
由流程图可知,发送清求到控制器,控制器第二个节点就是发送第二个请求就是去拿Handler,因此可知这里才是最核心代码。由图可知他取Handler最终要去找HandlerMapping,然后他再去拿一个Handler。那么为什么要去找HandlerMapping去要一个Handler呢?首先我们在配置控制器的时候有两种方式1.xml方式,2.注解的方式。因此spring源码他给我们不止一种控制器 。因为两种方式控制器 。因此spring并不知道我们使用的事哪一种控制器。因为两种控制器,spring去底层去找的控制的实现方式是不一样的。因此这就是为什么第二步他要去找Handler(控制器)的了。但是Handler怎么找的到呢?就是通过HandlerMapping这样一个处理器映射器。如代码可知他首先是判断当前HandlerMappers是否为空:this.handlerMappings
由此可看当前HandlerMappers有两个对象也就是两个Handler。因此可知上面说的,spring不止一个控制器;相当于他来这里面找他所要的控制器。一个是xml对应的,一个是注解对应的注:因此这里主要以xml方式进行讲解。注解形式其实一样,只不过去匹配注解对象的HandlerMapping以及HandlerAdapter).
那么接下来他会怎么处理呢?由源码得知,spring首先是遍历HandlerMappers,怎么遍历呢?他会问当前数组中有没有我这控制器。也就是代码中的mapping对应的是当前控制器
找到之后,他返回的是一个HandlerExecutionChain类型的Handle,这里面封装了一个BeanController,也就是我们自己的创建controlller,如果有配置拦截器我们还会封装一个拦截器(interceptor)
因此到这里我们就拿到了对应的也是最合适的Handler,然后返回给DispatcherServlet
然后到第二个方法:
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
获取控制器的适配器。也就是我们之前拿到了控制器,接下来要去执行控制器,也就是拿到控制器适配器中执行控制器。这里为什么要获取适配器呢?因为跟控制器映射器(也就是配置方式)一样。
你就有不同的适配器。因此适配器也不是一个。跟我们上面Handler原理一样。
接下来就是适配器去执行Handler
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
如果你有ModelAndView,就返回一个ModelAndView.然后返回给试图对象,然后把视图对象交给视图解析器,去渲染,最后响应给用户。
因此总结,spring提供了两种HandlerMapping以及三种HandlerAdapter
而它是怎么获取的呢springMVC初始化时就加载实例化,获取这些对象。他们是被配置在spring的SpringwebMVC架包的servlet架包中的DispatcherServlet.properties配置文件中