SpringMVC的DispatcherServlet详解

Spring MVC框架,与其他很多web的MVC框架一样:请求驱动;所有设计都围绕着一个中央Servlet来展开,它负责把所有请求分发到控制器;同时提供其他web应用开发所需要的功能。不过Spring的中央处理器,DispatcherServlet,能做的比这更多。它与Spring IoC容器做到了无缝集成,这意味着,Spring提供的任何特性,在Spring MVC中你都可以使用。

下图展示了Spring Web MVC的DispatcherServlet处理请求的工作流。熟悉设计模式的朋友会发现,DispatcherServlet应用的其实就是一个“前端控制器”的设计模式(其他很多优秀的web框架也都使用了这个设计模式)。

图21.1 Spring Web MVC处理请求的(高层抽象)工作流

DispatcherServlet其实就是个Servlet(它继承自HttpServlet基类),同样也需要在你web应用的web.xml配置文件下声明。你需要在web.xml文件中把你希望DispatcherServlet处理的请求映射到对应的URL上去。这就是标准的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>

In the preceding example, all requests starting with /example will be handled by the DispatcherServlet instance named example. In a Servlet 3.0+ environment, you also have the option of configuring the Servlet container programmatically. Below is the code based equivalent of the above web.xml example:

在上面的例子中,所有路径以/example开头的请求都会被名字为exampleDispatcherServlet处理。在Servlet 3.0+的环境下,你还可以用编程的方式配置Servlet容器。下面是一段这种基于代码配置的例子,它与上面定义的web.xml配置文件是等效的。

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {
        ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet());
        registration.setLoadOnStartup(1);
        registration.addMapping("/example/*");
    }

}

WebApplicationInitializer是Spring MVC提供的一个接口,它会查找你所有基于代码的配置,并应用它们来初始化Servlet 3版本以上的web容器。它有一个抽象的实现AbstractDispatcherServletInitializer,用以简化DispatcherServlet的注册工作:你只需要指定其servlet映射(mapping)即可。若想了解更多细节,可以参考基于代码的Servlet容器初始化一节。

上面只是配置Spring Web MVC的第一步,接下来你需要配置其他的一些bean(除了DispatcherServlet以外的其他bean),它们也会被Spring Web MVC框架使用到。

6.15 应用上下文ApplicationContext的其他作用)一节中我们聊到,Spring中的ApplicationContext实例是可以有范围(scope)的。在Spring MVC中,每个DispatcherServlet都持有一个自己的上下文对象WebApplicationContext,它又继承了根(root)WebApplicationContext对象中已经定义的所有bean。这些继承的bean可以在具体的Servlet实例中被重载,在每个Servlet实例中你也可以定义其scope下的新bean。

图21.2 Spring Web MVC中常见的context层级结构

DispatcherServlet的初始化过程中,Spring MVC会在你web应用的WEB-INF目录下查找一个名为[servlet-name]-servlet.xml的配置文件,并创建其中所定义的bean。如果在全局上下文中存在相同名字的bean,则它们将被新定义的同名bean覆盖。

看看下面这个DispatcherServlet的Servlet配置(定义于web.xml文件中):

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

有了以上的Servlet配置文件,你还需要在应用中的/WEB-INF/路径下创建一个golfing-servlet.xml文件,在该文件中定义所有Spring MVC相关的组件(比如bean等)。你可以通过servlet初始化参数为这个配置文件指定其他的路径(更多细节请参考下文)。

当你的应用中只需要一个DispatcherServlet时,只配置一个根context对象也是可行的。

图21.3 Spring Web MVC中的根context

要配置一个唯一的根context对象,可以通过在servlet初始化参数中配置一个空的contextConfigLocation来做到,如下所示:

<web-app>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/root-context.xml</param-value>
    </context-param>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

WebApplicationContext继承自ApplicationContext,它提供了一些web应用经常需要用到的特性。它与普通的ApplicationContext不同的地方在于,它支持主题的解析(详见21.9 主题Themes一小节),并且知道它关联到的是哪个servlet(它持有一个该ServletContext的引用)。WebApplicationContext被绑定在ServletContext中。如果需要获取它,你可以通过RequestContextUtils工具类中的静态方法来拿到这个web应用的上下文WebApplicationContext


21.2.1 WebApplicationContext中特殊的bean类型

Spring的DispatcherServlet使用了特殊的bean来处理请求、渲染视图等,这些特定的bean是Spring MVC框架的一部分。如果你想指定使用哪个特定的bean,你可以在web应用上下文WebApplicationContext中简单地配置它们。当然这只是可选的,Spring MVC维护了一个默认的bean列表,如果你没有进行特别的配置,框架将会使用默认的bean。下一小节会介绍更多的细节,这里,我们将先快速地看一下,DispatcherServlet都依赖于哪些特殊的bean来进行它的初始化。

bean的类型作用
HandlerMapping处理器映射。它会根据某些规则将进入容器的请求映射到具体的处理器以及一系列前处理器和后处理器(即处理器拦截器)上。具体的规则视HandlerMapping类的实现不同而有所不同。其最常用的一个实现支持你在控制器上添加注解,配置请求路径。当然,也存在其他的实现。
HandlerAdapter处理器适配器。拿到请求所对应的处理器后,适配器将负责去调用该处理器,这使得DispatcherServlet无需关心具体的调用细节。比方说,要调用的是一个基于注解配置的控制器,那么调用前还需要从许多注解中解析出一些相应的信息。因此,HandlerAdapter的主要任务就是对DispatcherServlet屏蔽这些具体的细节。
HandlerExceptionResolver处理器异常解析器。它负责将捕获的异常映射到不同的视图上去,此外还支持更复杂的异常处理代码。
ViewResolver视图解析器。它负责将一个代表逻辑视图名的字符串(String)映射到实际的视图类型View上。
LocaleResolver & LocaleContextResolver地区解析器 和 地区上下文解析器。它们负责解析客户端所在的地区信息甚至时区信息,为国际化的视图定制提供了支持。
ThemeResolver主题解析器。它负责解析你web应用中可用的主题,比如,提供一些个性化定制的布局等。
MultipartResolver解析multi-part的传输请求,比如支持通过HTML表单进行的文件上传等。
FlashMapManagerFlashMap管理器。它能够存储并取回两次请求之间的FlashMap对象。后者可用于在请求之间传递数据,通常是在请求重定向的情境下使用。

21.2.2 默认的DispatcherServlet配置

上一小节讲到,DispatcherServlet维护了一个列表,其中保存了其所依赖的所有bean的默认实现。这个列表保存在包org.springframework.web.servlet下的DispatcherServlet.properties文件中。

这些特殊的bean都有一些基本的默认行为。或早或晚,你可能需要对它们提供的一些默认配置进行定制。比如说,通常你需要配置InternalResourceViewResolver类提供的prefix属性,使其指向视图文件所在的目录。 这里需要理解的一个事情是,一旦你在web应用上下文WebApplicationContext中配置了某个特殊bean以后(比如InternalResourceViewResolver),实际上你也覆写了该bean的默认实现。比方说,如果你配置了InternalResourceViewResolver,那么框架就不会再使用beanViewResolver的默认实现。

21.16节 Spring MVC的配置中,我们介绍了其他配置Spring MVC的方式,比如通过Java编程配置或者通过MVC XML命名空间进行配置。它们为配置一个Spring MVC应用提供了简易的开始方式,也不需要你对框架实现细节有太多了解。当然,无论你选用何种方式开始配置,本节所介绍的一些概念都是基础且普适的,它们对你后续的学习都应有所助益。


21.2.3 DispatcherServlet的处理流程

配置好DispatcherServlet以后,开始有请求会经过这个DispatcherServlet。此时,DispatcherServlet会依照以下的次序对请求进行处理:

  • 首先,搜索应用的上下文对象WebApplicationContext并把它作为一个属性(attribute)绑定到该请求上,以便控制器和其他组件能够使用它。属性的键名默认为DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE
  • 将地区(locale)解析器绑定到请求上,以便其他组件在处理请求(渲染视图、准备数据等)时可以获取区域相关的信息。如果你的应用不需要解析区域相关的信息,忽略它即可
  • 将主题(theme)解析器绑定到请求上,以便其他组件(比如视图等)能够了解要渲染哪个主题文件。同样,如果你不需要使用主题相关的特性,忽略它即可
  • 如果你配置了multipart文件处理器,那么框架将查找该文件是不是multipart(分为多个部分连续上传)的。若是,则将该请求包装成一个MultipartHttpServletRequest对象,以便处理链中的其他组件对它做进一步的处理。关于Spring对multipart文件传输处理的支持,读者可以参考21.10 Spring的multipart(文件上传)支持一小节
  • 为该请求查找一个合适的处理器。如果可以找到对应的处理器,则与该处理器关联的整条执行链(前处理器、后处理器、控制器等)都会被执行,以完成相应模型的准备或视图的渲染
  • 如果处理器返回的是一个模型(model),那么框架将渲染相应的视图。若没有返回任何模型(可能是因为前后的处理器出于某些原因拦截了请求等,比如,安全问题),则框架不会渲染任何视图,此时认为对请求的处理可能已经由处理链完成了

如果在处理请求的过程中抛出了异常,那么上下文WebApplicationContext对象中所定义的异常处理器将会负责捕获这些异常。通过配置你自己的异常处理器,你可以定制自己处理异常的方式。

Spring的DispatcherServlet也允许处理器返回一个Servlet API规范中定义的 最后修改时间戳(last-modification-date) 值。决定请求最后修改时间的方式很直接:DispatcherServlet会先查找合适的处理器映射来找到请求对应的处理器,然后检测它是否实现了 LastModified 接口。若是,则调用接口的long getLastModified(request)方法,并将该返回值返回给客户端。

你可以定制DispatcherServlet的配置,具体的做法,是在web.xml文件中,Servlet的声明元素上添加一些Servlet的初始化参数(通过init-param元素)。该元素可选的参数列表如下:

可选参数解释
contextClass任意实现了WebApplicationContext接口的类。这个类会初始化该servlet所需要用到的上下文对象。默认情况下,框架会使用一个XmlWebApplicationContext对象。
contextConfigLocation一个指定了上下文配置文件路径的字符串,该值会被传入给contextClass所指定的上下文实例对象。该字符串内可以包含多个字符串,字符串之间以逗号分隔,以此支持你进行多个上下文的配置。在多个上下文中重复定义的bean,以最后加载的bean定义为准
namespaceWebApplicationContext的命名空间。默认是[servlet-name]-servlet


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring MVC是基于Spring框架MVC(Model-View-Controller)模式的Web开发框架。它提供了一种灵活、可扩展的方式来构建Web应用程序。下面是对Spring MVC的深入详解: 1. 请求处理流程:当客户端发送请求时,请求会被DispatcherServlet接收并进行处理。DispatcherServlet会根据请求的URL找到对应的处理器(Controller),并调用相应的方法进行处理。处理器可能会调用服务层(Service)进行业务逻辑处理,并将结果封装为Model对象。然后,处理器会选择合适的视图(View)进行渲染,并将Model对象传递给视图进行展示。最终,视图生成响应内容返回给客户端。 2. 控制器(Controller):控制器负责接收和处理客户端的请求。在Spring MVC中,控制器可以使用注解(如@Controller)或实现特定接口(如Controller接口)来定义。控制器方法可以通过方法参数获取请求参数、路径变量等信息,并通过方法返回值来指定响应结果。控制器方法可以返回逻辑视图名、ModelAndView对象、JSON数据等。 3. 视图解析:Spring MVC使用视图解析器来解析控制器方法返回的逻辑视图名,并将其转换为具体的视图对象。视图解析器可以根据视图名的前缀和后缀,自动匹配合适的视图实现。常见的视图实现包括JSP、Thymeleaf、Freemarker等。 4. 数据绑定:Spring MVC支持数据绑定,可以将请求参数绑定到控制器方法的参数、表单对象、模型对象等上。数据绑定可以通过注解(如@ModelAttribute、@RequestParam)或自动推断来进行。Spring MVC还支持数据格式转换和验证,可以自动将请求参数转换为指定类型,并对数据进行验证。 5. 拦截器(Interceptor):拦截器是Spring MVC提供的一种机制,用于对请求进行预处理和后处理。拦截器可以在请求进入控制器之前、视图渲染之前或请求完成之后执行特定的操作。例如,可以使用拦截器进行身份认证、日志记录等处理。 6. 异常处理:Spring MVC提供了异常处理机制,可以捕获控制器方法抛出的异常,并根据配置进行处理。可以通过注解(如@ExceptionHandler)或配置全局异常处理器(HandlerExceptionResolver)来定义异常处理逻辑。 7. 文件上传:Spring MVC提供了文件上传的支持。可以使用@RequestParam注解将文件上传到控制器方法的参数中,并通过MultipartFile对象获取文件内容、文件名等信息。 总而言之,Spring MVC是一个功能强大、灵活可扩展的Web开发框架。它通过MVC模式、请求处理流程、控制器、视图解析、数据绑定、拦截器、异常处理等特性,帮助开发人员构建高效、可维护的Web应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值