Spring mvc-核心 DispatcherServlet 详解

说明:本文摘自 swadian2008-作品,仅为方便学习,若作者各位哥老倌有需要可以去创作者家查看原文

1、核心Servlet:DispatcherServlet 介绍

与许多其他的 web 框架一样,Spring MVC 也是围绕前端控制器模式设计的,核心的 Servlet DispatcherServlet 为请求处理提供了共享算法,但是实际工作由可配置的委托组件执行的。这种设计非常灵活,可以支持不同的工作流。// 核心Servlet,其他组件可配置

DispatcherServlet 和其他 Servlet 一样,也需要通过一些配置去发现它的委托组件(请求映射、视图解析、异常处理等组件),这些配置可以是 Java 代码,也可以是 web.xml 文件。// 通过配置发现组件
下面是通过 Java 代码注册和初始化一个 DispatcherServlet 的例子,这些配置信息会被 Servlet 容器自动进行检测:

public class MyWebApplicationInitializer implements WebApplicationInitializer {
 
    @Override
    public void onStartup(ServletContext servletContext) {
 
        // 加载Spring web应用程序配置
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(AppConfig.class);
 
        // 创建并注册DispatcherServlet
        DispatcherServlet servlet = new DispatcherServlet(context);
        ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
        // 定义容器的初始化顺序
        registration.setLoadOnStartup(1);
        registration.addMapping("/app/*");
    }
}

2、DispatcherServlet 容器的上下文层次结构

DispatcherServlet 需要通过 WebApplicationContext 来加载自己的配置。DispatcherServlet 的上下文结构:
在这里插入图片描述
WebApplicationContext 的上下文结构:
在这里插入图片描述
WebApplicationContext 可以通过 getServletContext() 方法访问到关联 Servlet 的上下文。通过 RequestContextUtils 工具类又可以访问到 WebApplicationContext。// Servlet 和上下文绑定

对于许多应用程序来说,一个 WebApplicationContext 就足够了。但也可以使用一个带层次结构的上下文,在层次结构的上下文中,底层 WebApplicationContext 可以在多个 DispatcherServlet(或其他Servlet)之间进行共享,而每个 Servlet 又都可以有自己单独的子WebApplicationContext 配置。// 分层设计上下文

底层 WebApplicationContext 通常包含一些基础设施的 Bean,比如跨多个 Servlet 共享的数据存储实例和业务服务等。这些 Bean 可以被有效地继承,并且在特定的 Servlet 的子WebApplicationContext 中进行重写(即重新声明),该子 WebApplicationContext 通常包含给定的 Servlet 的本地 Bean。下图显示了这种关系:
在这里插入图片描述

下面的示例配置了一个 WebApplicationContext 的层次结构:

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
 
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { RootConfig.class };
    }
 
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { App1Config.class };
    }
 
    @Override
    protected String[] getServletMappings() {
        return new String[] { "/app1/*" };
    }
}

3、特殊类型的 Beans(web mvc 组件)

DispatcherServlet 需要通过特殊的 bean 来处理请求和响应。下边列出了 DispatcherServlet 中的一些特殊的 beans:

  • HandlerMapping:将一个请求映射到另一个处理程序,以及用于拦截器列表的前置处理和后置处理。两个主要的 HandlerMapping 实现,一个是 RequestMappingHandlerMapping,它支持带 @RequestMapping 注释的方法,另一个是 SimpleUrlHandlerMapping,它用来维护 URI 路径到处理程序的显式注册。// 映射请求路径到指定的方法

  • HandlerAdapter:帮助 DispatcherServlet 调用一个请求映射到的处理程序,该组件并不用管这些处理程序的实际调用(子类有具体的实现的调用逻辑)。例如,调用带注释的控制器需要去解析注释。HandlerAdapter 的主要目的是保护 DispatcherServlet 不受这些细节的影响。// 调用具体的方法

  • HandlerExceptionResolver:解决异常的策略,可能将异常映射到处理程序、HTML错误视图或其他目标

  • ViewResolver:视图解析,用来将程序返回的视图名称解析为对应的实际视图(呈现视图)。

  • LocaleResolver, LocaleContextResolver:解析客户端正在使用的区域和时区,以便能够提供国际化的视图。// 理解为国际化
    ThemeResolver:解决 web 应用程序可以使用的主题。例如,提供个性化的布局等。

  • MultipartResolver:用于处理文件上传

  • FlashMapManager:将一个请求发送给另一个请求,通常使用重定向实现。

    通过下边的图示,对以上组件的 beans 和 Spring MVC 的执行流程会有一个更加清晰的认知:
    在这里插入图片描述

4、Web MVC 的一些基础配置项

应用程序可以声明上述一些特殊类型的 beans,然后 DispatcherServlet 会从容器中去获取这些声明的 bean,如果没有找到对应类型的 bean,DispatcherServlet 就会使用默认的 bean 配置,默认配置的文件内容如下:DispatcherServlet.properties. // 如果不自定义 spring mvc 的组件,那么加载的就是 spring 自己实现的相关组件。

5、Servlet Config 容器的配置

下面的例子注册了一个DispatcherServlet:// 最原始的方式

public class MyWebApplicationInitializer implements WebApplicationInitializer {
 
    @Override
    public void onStartup(ServletContext container) {
        XmlWebApplicationContext appContext = new XmlWebApplicationContext();
        appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
 
        ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(appContext));
        registration.setLoadOnStartup(1);
        registration.addMapping("/");
    }
}

WebApplicationInitializer 是 Spring MVC 提供的一个接口,用来为 web 应用程序提供配置。这个接口的实现会自动被 SpringServletContainerInitializer 检测到(SpringServletContainerInitializer 本身会被 Servlet 自动加载)。另外,还可以使用该类的子类 AbstractDispatcherServletInitializer 提供配置,使用该子类配置 Servlet 会更加的方便,示例代码如下:// 代码中 AbstractAnnotationConfigDispatcherServletInitializer 是上述抽象类的子类

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
 
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }
 
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { MyWebConfig.class };
    }
 
    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

6、DispatcherServlet 请求处理过程

DispatcherServlet 处理请求的方式如下:

  1. 为请求绑定 WebApplicationContext 属性。

  2. 为请求绑定 locale resolver(区域解析器),如果不需要请求不要进行区域解析,则不需要区域解析器。

  3. 为请求绑定主题解析器,主要用来决定视图使用哪个主题。如果不使用主题,则可以忽略它。

  4. 如果是文上传请求,此处,该请求会被包装在 MultipartHttpServletRequest 中进行处理。// 点击这里了解文件的处理。

  5. 寻找适当的处理程序。如果找到对应的处理程序,则会运行与该处理程序(预处理器、后处理器和控制器)相关的执行链,返回一个用于呈现的模型或结果。

  6. 请求结果处理,如果返回模型,则呈现视图。

    自定义 DispatcherServlet 初始化参数:比如指定 WebApplicationContext 的加载位置,自定义异常处理方式等。
    

7、有关路径映射的问题

路径映射涉及都到路径的编码与解码等问题。主要工作是把请求路径和Handler(处理程序/方法)的路径进行匹配,使请求能匹配到指定的处理程序,在后续文章会详细介绍,此处只简要提及。// 详情请点击这里

8、拦截器

所有 HandlerMapping 的实现(方法)都可以被拦截器进行拦截。定义一个拦截器只需要实现 HandlerInterceptor 接口即可。// 拦截器是全局的,类似于AOP编程

package org.springframework.web.servlet;
public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }
 
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }
 
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

拦截器与过滤器的区别:

过滤器是Servlet规范,拦截器是Spring组件
在这里插入图片描述
具体区别图示:
在这里插入图片描述

使用的拦截器的更多注意事项,点击这里

9、异常处理

如果在请求期间抛出异常,DispatcherServlet 会将异常委托给 HandlerExceptionResolver bean 链来进行处理。HandlerExceptionResolver 的四个实现

  1. SimpleMappingExceptionResolver:异常类和错误视图之间的映射。用于在浏览器中呈现错误的页面。
  2. DefaultHandlerExceptionResolver:解析Spring MVC引发的异常,并将其映射到HTTP状态代码。
  3. ResponseStatusExceptionResolver:使用@ResponseStatus注释解决异常,并根据注释中的值将异常映射到HTTP状态代码。
  4. ExceptionHandlerExceptionResolver:通过调用@Controller或@ControllerAdvice类中的@ExceptionHandler方法来解决异常。参见@ExceptionHandler方法。

至此,Spring mvc 核心 DispatcherServlet 详解到此结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值