前言

Spring 是啥?

MVC 是啥?

Spring MVC 是一个基于 Spring 的 Web 框架.

在 Java Web 中,需要自己实现 HttpServlet,Spring MVC 对 平时用到的 Servlet 进行了一层封装.

Spring MVC

下面以一个完整的后端渲染流程大致说明一下.

原文 : 通过项目逐步深入了解Spring MVC(一)

在前后端分离项目中,无需 ModelAndView,直接返回 json 数据.

  1. DispatcherServlet(前端控制器) 接受所有的 Web 请求.

  2. 前端控制器请求 HandlerMapping(处理器映射器) 查找 Handler.(Handler 也就是 Controller 层)

可根据 xml 配置,注解查找.(包括URL, Http方法, 请求报文头和请求参数 Cookie 等)

  1. HandlerMapping 向 DispatcherServlet 返回 Handler.

  2. DispatcherServlet 调用 HandlerAdapter(处理器适配器) 去执行 Handler.

  3. HandlerAdapter 执行 Handler.

  4. Handler 执行完成返回 ModelAndView 给 HandlerAdapter.

  5. HandlerAdapter 向 DispatcherServlet 返回 ModelAndView.

ModelAndView 是 Spring MVC 的一个底层对象,包括 Model 和 View.

  1. DIspatcherServlet 请求 ViewResolver(视图解析器) 去进行视图解析.

根据逻辑视图名解析成真正的视图

  1. ViewResolver 向 DispatcherServlet 返回 View

View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等)

  1. DispatcherServlet 进行视图渲染

    视图渲染将模型数据(在 ModelAndView 中)填充到 request 域

    这一层就是 jsp,Thymeleaf 页面开发吧?

  2. DispatcherServlet 向用户相应结果

源码分析

DispatcherServlet

DispatcherServlet 的继承链 :

DispatcherServlet –> FrameworkServlet –> HttpServletBean –> HttpServlet

DispatcherServlet 其实是 HttpServlet 的子类.本质上也是一个 Servlet.

详情可见 : HttpServlet

大概介绍一下,Java EE 开发时,会继承 HttpServlet,实现里面的 doGet(),doPost() 等方法来相应 Http 请求.

public class Login extends javax.servlet.http.HttpServlet{
 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  // ... 
 }
}

Spring MVC 把这种细节屏蔽了.

看构造方法,

public DispatcherServlet(WebApplicationContext webApplicationContext) {
		super(webApplicationContext);
		setDispatchOptionsRequest(true);
	}

这里传入了一个 WebApplicationContext.

看 : Spring 启动流程

ApplicationContext 是 Spring IOC 的容器(也称 上下文),WebApplicationContext 继承自 ApplicationContext,为 Spring MVC 提供上下文环境.使之在 Web 环境可以访问 Spring 的上下文.有了这个,相应就可以通过 Spring 来管理 Bean 之类的啦…

通过 WebApplicationContext,可以访问 :

  1. ServletContext

Web 服务器提供

  1. request, session, globalsession

  2. HttpServletRequest

服务器获取客户端数据

  1. HttpServletResponse

服务器向客户端传递数据

至于 WebApplicationContext 的创建,则由 Spring 来完成.

在一个 Spring MVC 项目中,通过在 web.xml 中配置 :

<listener>
		<description>spring listener</description>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

ContextLoaderListener 指定 Web 应用程序启动时载入 IOC 容器.

// todo 具体怎么加载呢?

过程

SpringMVC源码分析系列-精简

// spring-webmvc
// org.springframework.web.servlet.DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	...
	try {
		ModelAndView mv = null;
		Exception dispatchException = null;
		try {
			processedRequest = checkMultipart(request);
			multipartRequestParsed = (processedRequest != request);
			//1.调用handlerMapping获取handlerChain
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null || mappedHandler.getHandler() == null) {
				noHandlerFound(processedRequest, response);
				return;
			}
			// 2.获取支持该handler解析的HandlerAdapter
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
			...
			// 3.使用HandlerAdapter完成handler处理
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
			if (asyncManager.isConcurrentHandlingStarted()) {
				return;
			}
			// 4.视图处理(页面渲染)
			applyDefaultViewName(request, mv);
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}
		catch (Exception ex) {
			dispatchException = ex;
		}
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
	...
}

对应上文 Spring MVC 的 11 个步骤…

// todo [先到此]

Spring MVC 如何以统一的方式,将数据纳入不同的视图并显示?

服务端渲染才会考虑这一点.

底层(Servlet)是 HttpServletResponse.

将视图数据通过 HttpServletResponse 输出前,借助不同的视图技术 API,结合数据和模板文件,生成最终结果.