Spring MVC本质是一个Servlet,Servlet运行需要一个Servlet容器,如常用的Tocmat。Servlet容器帮我们统一做了像底层Socket连接那种通用又麻烦的工作,让开发变得轻松,只需要按照Servlet的接口做就可以。
Spring MVC又在此基础上提供了一套通用的解决方案,Servlet都可以不用写,只关注业务就可以。
下面以Tomcat为例分析Servlet容器的结构和原理。
Tomca可以分为两大部分:连接器和容器,连接器专门用于处理网络连接相关的事情,如Socket连接、request封装、连接线程池维护等工作,容器用来存放我们编写的网站程序,Tomcat中一共有4层容器:Engine、Host、Context和Wrapper。一个Wrapper对应一个Servlet,一个Context对应一个应用,一个Host对应一个站点,Engine是引擎,一个容器只有一个。Context和Host的区别是Host代表站点,如不同的域名,而Context表示站点下的一个应用。一套容器和多个连接器组成一个Service,一个Tomcat中可以有多个Service。
Servlet接口一共定义了5个方法,其中init方法和destroy用于初始化和销毁Servlet,整个生命周期中只会被调用一次;service方法实际处理请求;getServletConfig方法返回的ServletConfig,可以获取到配置Servlet时使用init-param配置的参数,还可以获取ServletContext;getServletlnfo方法可以获取到一些Servlet相关的信息,如作者、版权等,这个方法需要自己实现,默认返回空字符串。
Java提供了两个Servlet的实现类:GenericServlet和HttpServlet。
GenericServlet主要做了三件事:①实现了ServletConfig接口,让我们可以直接调用ServletConfig中的方法;②提供了无参的init方法;③提供了log方法。
HttpServlet主要做了两仲事:①将ServletRequest和ServletResponse转换为了HttpServletRequest和HttpServletResponse;②根据Http请求类型(如Get、Post等)将请求路由到了7个不同的处理方法,这样在编写代码时只需要将不同类型的处理代码编写到不同的方法中就可以了,如常见的doGet、doPost方法就是在这里定义的。
Spring MVC的本质是个Servlet,这个Servlet继承自HttpServlet。Spring MVC中提供了三个层次的Servlet:HttpServletBean、FrameworkServlet和DispatcherServlet,下层继承上层,HttpServletBean直接继承自Java的HttpServlet。
HttpServletBean用于将Servlet中配置的参数设置到相应的属性中,FrameworkServlet初始化了Spring MVC中所使用的WebApplicationContext,具体处理请求的9大组件是在DispatcherServlet中初始化的。
Spring MVC的结构就总结到这里,接下来总结Spring MVC的请求处理过程。SpringMVC中请求的处理主要在DispatcherServlet中,不过它上一层的FrameworkServlet也做了一些工作,首先它将所有类型的请求都转发到processRequest方法,然后在processRequest方法中做了三件事:①调用了doService模板方法具体处理请求,doService方法在DispatcherServlet中实现;(参将当前请求的LocaleContext和ServletRequestAttributes在处理请求前设置到了LocaleContextHolder和RequestContextHolder,并在请求处理完成后恢复;③请求处理完后发布一个ServletRequestHandledEvent类型的消息。
DispatcherServlet在doServic方法中将webApplicationContext、IocaleResolver、themeResolver、themeSource、FlashMap和FlashMapManager设置到request的属性中以方便使用,然后将请求交给doDispatch方法进行具体处理。
DispatcherServlet的doDispatch方法按执行过程大致可以分为4步:①根据request找到Handler;②根据找到的Handler找到对应的HandlerAdapter;③用HandlerAdapter凋用Handler处理请求;④调用processDispatchResult方法处理Handler处理之后的结果(主要处理异常和找到View并渲染输出给用户)。这4步中的每一步又有自己复杂的处理过程,详细内容这里就不介绍了,21.2节会再和大家一起回顾。
前面介绍的Handler、HandlerMapping和HandlerAdapter的关系,Handler是具体干活的工具,HandlerMapping用来找出需要的Handler,HandlerAdapter是怎么具体使用Handler干活,可以理解为使用工具的人。
一般做事情都是这个步骤,先找到工具,然后找到使用工具的人,最后人使用工具干活。这种思想就是Spring MVC的灵魂,它贯穿整个Spring MVC。上面说的Handler是MVC中的C层,其实Spring MVC在MVC三层使用的都是这种思想,在V层也就是View层干活的工具是View,查找View使用的是ViewResoLver和RequestToViewNameTranslator,因为View是标准的格式,使用非常简单,所以就没有"使用的人"这个角色;在M层也就是Model层,这层干活的就多了,注释了@ModelAttribute的方法、SessionAttribute、FlashMap、Model以及需要执行的方法的参数和返回值等都属于这一层,HandlerMethodArgumentResolver和HandlerMethodReturn ValueHandler、ModeIFactory和FlashMapManager是这一层中"使用的人",HandlerMethodArgumentResolver和HandlerMethodReturn ValueHandler同时还担任着"查找共具"的角色。
因为Model层贯穿于Controller层和View层之中,所以很容易将其当作那两层中的内容,其实Model层才是Spring MVC最复杂的地方。