springMVC学习一 工作机制

SpringMVC概述

Spring Web MVC 是最初建立在 Servlet API 之上的 Web 框架,从一开始就包含在 Spring Framework 中。 正式名称“Spring Web MVC”来自其源模块(spring-webmvc)的名称,但一般被称之为“Spring MVC”。与 Spring Web MVC 并行,Spring Framework 5.0 引入了一个响应式的Web 框架,其名称“Spring WebFlux”也基于其源模块 (spring-webflux)。

Spring与其他web框架整合思路 

spring 框架可以和其他任何MVC框架进行整合,并不是必须和Spring web MVC框架进行整合。

整合的方法就是通过spring框架的ContextLoaderListener来启动spring的根应用程序上下文(root application context),在ContextLoaderListener中的方法initWebApplicationContext中,会把创建的spring根上下文设置成ServletContext的属性。属性名为"org.springframework.web.context.WebApplicationContext.ROOT"。

如果其他MVC框架要想获取spring的根应用上下文,可以通过WebApplicationContextUtilsgetWebApplicationContext方法

 

DispatcherServlet介绍

Spring 的 Web MVC 框架与许多其他 Web MVC 框架一样,是请求驱动的,围绕一个中央 Servlet 设计,该 Servlet 将请求分派给控制器并提供其他功能以促进 Web 应用程序的开发。 然而,Spring 的 DispatcherServlet 不仅仅如此。 它与 Spring IoC 容器完全集成,因此允许您使用 Spring 具有的所有其他功能。

Spring Web MVC DispatcherServlet 的请求处理工作流程如下图所示。 精通模式的读者会认识到 DispatcherServlet 是“前端控制器”设计模式的一种表达(这是 Spring Web MVC 与许多其他领先的 Web 框架共享的模式)

DispatcherServlet实际上 是一个 Servlet(它继承自 HttpServlet 基类),因此在 Web 应用程序的 web.xml 中声明。 您需要通过在同一 web.xml 文件中使用 URL 映射来指定希望 DispatcherServlet 处理的请求。 这是标准的 Java EE Servlet 配置; 以下示例显示了这样的 DispatcherServlet 声明和映射:

<web-app>
     <servlet>
         <servlet-name>example</servlet-name>
         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
         <load-on-startup>1</load-on-startup>
     </servlet>
     <servlet-mapping>
         <servlet-name>example</servlet-name>
         <url-pattern>/example/*</url-pattern>
     </servlet-mapping>
</web-app>

 

Spring与SpringMVC整合的父子容器

在 Web MVC 框架中,每个 DispatcherServlet 都有自己的 WebApplicationContext,它继承了根 WebApplicationContext 中已经定义的所有 bean。 根 WebApplicationContext 包含所有其他上下文和 Servlet 实例之间共享的基础设施 bean。 这些继承的 bean 可以在特定于 servlet 的作用域中被覆盖。

默认情况下,在初始化 DispatcherServlet 时,Spring MVC 会在Web 应用程序的 WEB-INF 目录中查找名为 [servlet-name]-servlet.xml 的文件,在[servlet-name]-servlet.xml中定义的bean将会被创建。也可以在配置DispatcherServlet时的初始化参数中配置 应用上下文配置文件的位置。

配置代码如下:

<servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <!--
            servlet默认是懒加载,也就是当servlet第一次被访问时,才会加载被访问的servlet,
            如果配置了<load-on-startup>,就是在tomcat容器启动时就加载当前servlet
        -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <!--
            / 匹配除jsp以外的所有的请求路径
            /* 匹配所有请求路径
            *.do 匹配所有以.do结尾的所有请求
        -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

上述配置种,如果没有在<init-param>种指定配置文件位置,则采用默认的配置文件/WEB-INF/dispatcherServlet-servlet.xml

 

配置注意事项

配置DipatcherServlet时有几个注意的点:

  • "/" 代表处理.jsp以外的所有请求都会被DispatcherServlet拦截
  • “/*” 代表所有的请求路径都会被拦截
  • *.do 匹配所有以.do为结尾的所有请求

因此DispatcherServlet本身没有处理html、css、js、图片等静态资源的能力,所以需要放行静态资源的请求或者交给有能力处理静态资源的组件。

第一种:SpringMVC自己处理静态资源,但是需要指明那些请求是请求静态资源

采取<mvc:resources >

 <mvc:annotation-driven />
 <mvc:resources location="/img/" mapping="/img/**"/>   
 <mvc:resources location="/js/" mapping="/js/**"/>    
 <mvc:resources location="/css/" mapping="/css/**"/>  

 

location元素表示webapp目录下的static包下的所有文件;

mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b;

该配置的作用是:DispatcherServlet不会拦截以/static开头的所有请求路径,并当作静态资源交由Servlet处理。

第二种:SpringMVC自己不处理静态资源,由tomcat种的默认的Servlet来处理

采用<mvc:default-servlet-handler />

<mvc:default-servlet-handler />

在springMVC-servlet.xml中配置<mvc:default-servlet-handler />后,会在Spring MVC上下文中定义一个org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它会像一个检查员,对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。

 

一般Web应用服务器默认的Servlet名称是"default",因此DefaultServletHttpRequestHandler可以找到它。如果你所有的Web应用服务器的默认Servlet名称不是"default",则需要通过default-servlet-name属性显示指定:

<mvc:default-servlet-handler default-servlet-name="所使用的Web服务器默认使用的Servlet名称" />

 

 

 

HandlerMapping

本质是一个接口,在HandlerMapping的实现类中,有一个属性urlMap,是一个LinkedHashMap,在这个urlMap中  key就是程序员自己编写的controller(也就是处理器)的逻辑路径,例如我们用注解@RequestMapping("/test"),设置的"test",它就是urlMap中的一个key。那么value就是程序员编写的这个Controller。前端控制器(DispatcherServlet)解析出来请求路径后,就去这个处理器映射器中根据请求路径获取要执行的那个controller。

参考别处:HandlerMapping 将会把请求映射为HandlerExecutionChain 对象(包含一个Handler 处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象,通过这种策略模式,很容易添加新的映射策略;

 下面是一个简单最早的一种配置,现在都使用注解进行controller进行配置

<!-- 注册  处理器,也就是controller -->
    <bean id="handler" class="com.caopeng.controller.DemoController"></bean>
    
    
    <!-- 注册HandlerMapping  处理器映射器
        会根据url请求解析出应该调用哪一个 处理器,但是调用并不是处理器映射器调用
     -->
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="urlMap">
            <map>
                <!-- key解析出来的请求的逻辑名
                    value-ref代表要调用的控制器
                 -->
                <entry key="demo" value-ref="handler" ></entry>
            </map>
        </property>
    </bean>

 

处理器的编写代码:早期的写法要实现Controller接口,现在都是用注解进行配置

public class DemoController implements Controller{

    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("执行了springmvc的控制器");
        //具备视图和传值的功能
        ModelAndView modelAndView =new ModelAndView("main");
        
        return modelAndView;
    }

}

 

 

HandlerAdapter

根据处理器映射器 返回的处理器, 把处理器(controller)进行调用

配置如下:

<!-- 注册  处理器适配器,处理器适配器会调用  处理器 
        处理器适配器可以不用配置,会走默认值
    -->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

 

 

参考别处:HandlerAdapter 将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;HandlerAdapter 将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView 对象(包含模型数据、逻辑视图名);

ViewResovler

视图解析器.解析结果,准备跳转到具体的物理视
参考别处:ModelAndView的逻辑视图名——> ViewResolver, ViewResolver 将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;

配置如下:

<!-- 在spring容器中 ,注册视图解析器
        同样视图解析器也可以不用配置,也会走默认值
        InternalResourceViewResolver的父类中有两个属性:prefix,suffix  代表前缀和后缀
        ModelAndView modelAndView =new ModelAndView("main");
        前缀和后缀会对ModelAndView中的参数进行拼接,拼接成"/main.jsp",
        一般请情况下,我们会使用默认的视图解析器,但是有时候我们会在WebContent下建立一个page目录用来存放
        jsp文件,此时在写ModelAndView modelAndView =new ModelAndView("main.jsp");是,需要前面加上
        page/main.jsp,为了省略page/一般会把prefix配置成page/
        
        在返回ModelAndView时,默认会走请求转发,在InternalResourceViewResolver父类UrlBasedViewResolver
        中有
        public static final String REDIRECT_URL_PREFIX = "redirect:";
        public static final String FORWARD_URL_PREFIX = "forward:";
        可以通过配置让其走重定向
        
     -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

 

 

SpringMVC请求处理过程

核心架构的具体流程步骤如下:


  1. 首先用户发送请求——>DispatcherServlet:前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
  2. DispatcherServlet——>HandlerMapping: HandlerMapping 将会把请求映射为HandlerExecutionChain 对象(包含一个Handler 处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
  3. DispatcherServlet——>HandlerAdapter:HandlerAdapter 将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
  4. HandlerAdapter——>处理器功能处理方法的调用:HandlerAdapter 将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView 对象(包含模型数据、逻辑视图名);
  5. ModelAndView的逻辑视图名——> ViewResolver: ViewResolver 将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;
  6. View——>渲染:View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;
  7. 返回控制权给DispatcherServlet:由DispatcherServlet返回响应给用户,到此一个流程结束。

 

下边两个组件通常情况下需要开发:

Handler:处理器,即后端控制器用controller表示。

View:视图,即展示给用户的界面,视图中通常需要标签语言展示模型数据。

 

 

SpringMVC原理图:

 

 

看到这个图大家可能会有很多的疑惑,现在我们来看一下这个图的步骤:(可以对比MVC的原理图进行理解)

第一步:用户发起请求到前端控制器(DispatcherServlet)

第二步:前端控制器请求处理器映射器(HandlerMappering)去查找处理器(Handle):通过xml配置或者注解进行查找

第三步:找到以后处理器映射器(HandlerMappering)像前端控制器返回执行链(HandlerExecutionChain)

第四步:前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)去执行处理器(Handler)

第五步:处理器适配器去执行Handler

第六步:Handler执行完给处理器适配器返回ModelAndView

第七步:处理器适配器向前端控制器返回ModelAndView

第八步:前端控制器请求视图解析器(ViewResolver)去进行视图解析

第九步:视图解析器像前端控制器返回View

第十步:前端控制器对视图进行渲染

第十一步:前端控制器向用户响应结果

 

 

参考内容:

https://www.cnblogs.com/fangqi/archive/2012/10/28/2743108.html

 

posted @ 2018-10-13 12:32  阿瞒123  阅读(172)  评论(0编辑  收藏  举报