什么是Spring MVC

spring MVC是遵循MVC架构思想,基于Spring Container Core和AOP等技术,实现的轻量级web框架,用于简化我们日常Web开发。

处理请求的过程

处理请求的过程是用了前端控制器处理模式:

  • 前端控制器(Front Controller)- 处理应用程序所有类型请求的单个处理程序,应用程序可以是基于 web 的应用程序,也可以是基于桌面的应用程序。
  • 调度器(Dispatcher)- 前端控制器可能使用一个调度器对象来调度请求到相应的具体处理程序。
  • 视图(View)- 视图为请求而创建的对象。

总体流程

  1. 首先用户发送请求 ——> DispacherServlet,接收请求分发给对应的处理器。

  2. DispacherServlet ——> HandlerMapping,HandlerMapping根据请求URL找到对应的HanderMethod(Controller方法)和HandlerInterceptor。

  3. DispacherServlet ——> HandlerAdapter,根据handler找到适合的适配器(包含很多resolver)。

  4. HandlerAdapter ——> 处理器方法的调用,调用各种处理器和HanderMethod(Controller方法)完成请求的处理,并返回一个ModelAndView 对象(包含模型数据、逻辑视图名);

  5. ModelAndView 的逻辑视图名——> ViewResolver,ViewResolver 将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;

  6. View——>渲染,View 会根据传进来的Model 模型数据进行渲染,此处的Model 实际是一个Map 数据结构,因此 很容易支持其他视图技术;

  7. 返回控制权给DispatcherServlet,由DispatcherServlet 返回响应给用户,到此一个流程结束。

因为现在都是前后端分离项目,5-6步可以忽略。

下面为具体步骤:

1. tomcat容器使用线程池异步处理请求

使用的也是JUC中的ThreadPoolExecutor创建线程池,这里需要说明下任务类型是NioEndpoint$SocketProcessor,类的继承&实现结构如下:

,使用的是ThreadPoolExecutor#execute直接执行TaskThread$WrappingRunnable,没用使用常用的submit。submit会把Runnable/Callable统一封装成FutureTask方便通过它拿到结果,所以他们的调用栈不一样。

tomcat请求的调用栈

注意:run后面的行为-1,说明不是java程序调用应该是JVM调用的,本来前面的调用栈是通过ThreadPoolExecutor的runWorker中的task.run()发起进而执行任务的,但是因为FutureTask需要收集结果所以需要执行FutureTask中的run。

2. 调用HttpServlet#service

从标准public service方法中接收标准的HTTP请求,并将其发送到此类中定义的doMethod方法。

根据request的Method进入不同的方法处理,这里笔者发起的是post请求所以进入的是doPost。

3.FrameworkServlet#processRequest

处理请求,发布事件,而不管结果如何。

可以看到初始化了上下文,核心调用doService方法。

4. DispatcherServlet#doService

公开dispatcherservlet-specific的请求属性,委托公开给doDispatch实际调度。

可以看到设置了许多request属性比如handler、view对象,包括applicationcontext(从容器中拿到自定义处理类),实际调度进入doDispatch处理。

4.1 获得HandlerExecutionChain

进入getHandler(processedRequest)

按序遍历所有的HandlerMapping,找到请求的HandlerExecutionChain。

下面我们看看HandlerMapping是怎么通过请求映射到具体的HandlerExecution。

RequestMappingHandlerMapping#getHandlerInternal

可以看到根据lookupPath找到具体的HandlerMethod。

4.2 获得HandlerAdapter

这里根据HandlerMethod获得了RequestMappingHandlerAdapter,可以看到里面包含很多resolver用来处理请求和响应。

4.3调用handlerAdapter的handle进行具体处理

最近面试的小伙伴很多,对此我整理了一份Java面试题手册:基础知识、JavaOOP、Java集合/泛型面试题、
Java异常面试题、Java中的IO与NIO面试题、Java反射、Java序列化、Java注解、多线程&并发、JVM、Mysql、Redis、
Memcached、MongoDB、Spring、SpringBoot、SpringCloud、RabbitMQ、Dubbo、MyBatis、ZooKeeper、数据结构、算法、
Elasticsearch、Kafka、微服务、Linux等等。可以分享给大家学习。【持续更新中】领取方式【999】就可以领取资料了