SpringMVC运行机制详解——学好基本功,走路好轻松

SpringMVC运行机制详解——学好基本功,走路好轻松

说明:了解SpringMVC运行机制,有利于加深对SpringMVC框架的理解、在开发过程中能够快速定位到问题所在。同时对搭建SSM项目基础配置更加理解。总之,好处多多;

SpringMVC基本概念

SpringMVC框架:属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面(来自百度百科)。总而言之,SpringMVC框架属于Spring架构中的组成部分。在实际开发中,它主要负责HTTP请求接收、数据处理、请求响应等web层功能实现;故SpringMVC也称为Web层框架;它的设计架构是基于MVC架构。

MVC架构概念

M(Model)模型、V(View)视图、C(Controller)控制器三层分离的软件设计思想;主要目的就让M模型层和V视图层进行分离,只专注实现自己的功能。它们之间的交互的通过C控制器层进行协调交。MVC分层的设计思想降低了代码之间的耦合,有利于代码维护。MVC架构图如下所示:
SpringMVC运行机制详解——学好基本功,走路好轻松_第1张图片

耦合度:是指业务代码之间相互依赖、不同功能代码分层不明确。杂糅在一起,类似于的线团,如下图所示:左图就是耦合度高的、有图就是耦合度低的;

SpringMVC基本结构

SpringMVC好比一辆车,由很多部件一起结合组成SpringMVC框架。组成SpringMVC部件主要有DispatcherServlet(分发器)、HandlerMapping(处理映射器)、HandlerAdapter(处理适配器)、ViewResolver(视图解析器)等主要部件组成。

  1. DispatcherServlet(分发器):它属于SpringMVC核心,好比汽车的发动机的重要性。主要用来接收请求、相应结果、调度其他组件的处理/响应请求。由于它的存在,降低了各个组件之间的耦合;
  2. HandlerMapping(处理映射器):根据请求的URL去匹配程序中以“配置/注解”的方式配置的Handler,然后返回Handler处理器链。
  3. HandlerAdapter(处理适配器):根据规则去执行相应的Handler处理器,返回的是处理器处理后的结果;
  4. ViewResolver(视图解析器):将适配器返回的结果ModelAndView,解析成相应的View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。

总结:以上主要组件都是围绕着DispatcherServlet(分发器)进行调度的。它们之间不能直接交互。SpringMVC流程图如下所示:
SpringMVC运行机制详解——学好基本功,走路好轻松_第2张图片

SpringMVC源码分析(看不懂记住上面就够了,等知识储备多了再学习)

  <servlet>
    <servlet-name>springmvcservlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    <init-param>
      <param-name>contextConfigLocationparam-name>
      <param-value>classpath:spring-mvc.xmlparam-value>
    init-param>
    <load-on-startup>1load-on-startup>
  servlet>

建议用Idea查看代码,方便的不要不要的。用ctrl+鼠标单击DispatcherServlet进入源码文件;先来看DispatcherServlet源码继承/实现关系图。如下图所示:
SpringMVC运行机制详解——学好基本功,走路好轻松_第3张图片

说明:以下根据源码分析DispatcherServlet运行机制流程,不会很具体讲解各个方法的作用;

第一问:DispatcherServlet怎样得到用户的HTTP请求?

从上图可知,DispatcherServlet继承了HttpServlet,用过struts的都知道HtppServlet的作用。它是用处理HTTP请求的。具体自行百度。HttpServlet.class源码方法汇总如下:
SpringMVC运行机制详解——学好基本功,走路好轻松_第4张图片

注意红线标记的地方。类DispatcherServlet继承了抽象类FrameworkServlet。并且在抽象类FrameworkServlet中覆盖了HttpServlet中的service方法。覆盖方法源码如下:

/**
*FrameworkServlet.class源码(行数:432——440)
**/
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
        if (httpMethod != HttpMethod.PATCH && httpMethod != null) {
            super.service(request, response);
        } else {
            this.processRequest(request, response);
        }

    }

这说明了当HTTP请求过来时,会执行以上方法,如果HTTP请求正常,则调用HttpServlet类中service方法。判断是否请求类型,然后回调FrameworkServlet抽象类中的doGet/doPost方法。最终执行processRequest方法。processRequest源码如下图所示:
SpringMVC运行机制详解——学好基本功,走路好轻松_第5张图片

注意图标记的地方;doService是抽象类FrameworkServlet中的抽象方法。并且在子类DispatcherServlet中实现了。

总结:到这为止,知道了DispatcherServlet是通过继承抽象类FrameworkServlet,抽象类FrameworkServlet重写了HttpServlet类的service方法得到HTTP请求;

第二问:HandlerMapping、HandlerAdapte和ViewResolver是怎样初始化?
先看HttpServletBean.class类中init方法源码。如下所示:

/**
* HttpServletBean.class中66-85行
**/
public final void init() throws ServletException {
        PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
        if (!pvs.isEmpty()) {
            try {
                BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
                ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
                bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
                this.initBeanWrapper(bw);
                bw.setPropertyValues(pvs, true);
            } catch (BeansException var4) {
                if (this.logger.isErrorEnabled()) {
                    this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
                }

                throw var4;
            }
        }

        this.initServletBean();
    }

类HttpServletBean中的init()重写了类servlet中的init方法。init 方法的执行时刻跟servlet 配置中的load-on-startup标签有关,如下图示所示:
SpringMVC运行机制详解——学好基本功,走路好轻松_第6张图片
如果值大于等于 0,则在 Servlet 实例化的时候执行,间隔时间由具体的值决定,值越大,则越迟执行。如果小于 0 或者没有配置,则在第一次请求的时候才同步执行 (该方法只执行一次);
其中init方法中涉及到了BeanWrapper,PropertyValues,ResourceLoader,initServletBean方法

  1. PropertyValues:获取Web.xml里面的servlet的init-param;
  2. BeanWrapper:封装了bean的行为,提供了设置和获取属性值,它有对应的BeanWrapperImpl;
  3. ResourceLoader:接口仅有一个getResource(String location)的方法,可以根据一个资源地址加载文件资源。classpath:这种方式指定SpringMVC框架bean配置文件的来源;
  4. initServletBean():在HttpServletBean类只是提供了参考,具体实现实在子类FrameworkServlet中。源码如下:
    SpringMVC运行机制详解——学好基本功,走路好轻松_第7张图片

initServletBean方法调用了initWebApplicationContext方法。用来初始化springMVC上下文环境。同时通过synchronized关键同步执行onRefresh()方法。源码如下:
SpringMVC运行机制详解——学好基本功,走路好轻松_第8张图片
onRefresh方法在FrameworkServlet只是提供参考,具体实现实在子类DispatcherServlet中。源码如下:
SpringMVC运行机制详解——学好基本功,走路好轻松_第9张图片
onRefresh方法中调用了initStrategies方法。在initStrategies初始化了SpringMVC的组件。

//初始化上传文件解析器
initMultipartResolver(context);

//初始化本地解析器
initLocaleResolver(context);

//初始化主题解析器
initThemeResolver(context);

//初始化映射处理器
initHandlerMappings(context);

//初始化适配器处理器
initHandlerAdapters(context);

//初始化异常处理器
initHandlerExceptionResolvers(context);

//初始化请求到视图名翻译器
initRequestToViewNameTranslator(context);

//初始化视图解析器
initViewResolvers(context);

总结:目前分析的源码中只涉及了3个类,分别是:FrameworkServlet、DispatcherServlet、HttpServletBean。它们各自做了什么事情?

  1. HttpServletBean是主要是获取web.xml配置文件中的标签的值;
  2. FrameworkServlet主要实现了初始化SpringMVC上下文环境;
  3. DispatcherServlet主要实现了SpringMVC各个组件的初始化;

你可能感兴趣的:(JavaWeb,springmvc运行机制,springmvc原理,源码分析)