Spring MVC(一)— DispatcherServlet

news/2024/5/19 12:15:57 标签: spring, mvc, java, 责任链模式, 代理模式

 DispatcherServlet 是Spring MVC框架的HTTP 请求处理器的中央调度器。它具有以下的功能:

1)基于IoC容器JavaBean配置机制。

2)使用HandlerMappingl来实现请求到处理器的路由映射。

3)使用HandlerAdapter 来处理不同的处理器。

4)处理器抛出的异常解决策略由HandlerExceptionResolver指定。

5)视图解析策略可以通过ViewResolver实现指定。

6)文件上传策略通过MultipartResolver来确定。

7)Locale解析策略由LocaleResolver确定。

8)主题解析策略由ThemeResolver确定。

1 WebApplicationinitializer

Spring 中用于以编程方式配置ServletContext,来替代web.xml的方式。其本身的执行由任何Servlet3.0 容器自动引导。

图 WebApplicationInitializer UML

public class CustomWebApplicationInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext webApplicationContext = new AnnotationConfigWebApplicationContext();
        webApplicationContext.register(CustomAutowireConfigurer.class); // 配置注解方式的IoC容器
        DispatcherServlet dispatcherServlet = new DispatcherServlet(webApplicationContext); // 可以在servlet中使用IoC容器
        ServletRegistration.Dynamic dynamic = servletContext.addServlet("dispatcherServlet", dispatcherServlet);
        dynamic.addMapping("/app/*"); // 所以以/app开头的请求都会映射到servlet
    }
}

相当于下面的web.xml

<web-app>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/app-context.xml</param-value>
    </context-param>

    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>
</web-app>

1.1 运行原理

javax.servlet.ServletContainerInitializer 接口是Servlet 3.0规范中定义的,当Servlet 3.0 的容器启动时,会调用其onStartup 方法。

图 ServletContainerInitializer UML

而Spring MVC通过SPI的方式,通过SpringServletContainerInitializer类来实现这个接口从而提供服务。在onStartup 方法中,会遍历IoC容器中定义的所有WebApplicationInitializer实例,并执行其onStart方法。

1.2 Servlet配置

AbstractDispatcherServletInitializer的customizeRegistration(ServletRegistration.Dynamic registration)方法用来定制Servlet。

图 Dynamic 的UML

1.2.1 WebMvcConfigurer

是一个用于配置Spring MVC的接口。允许你自定义视图解析器、消息转换器、拦截器、静态资源处理器等。使用时需将它的实例注册为容器的bean,并在其实现类上加上@EnableWebMvc注解。

图 WebMvcConfigurer UML

1.3 DispatcherServlet处理请求的流程

DispatcherServlet 处理请求的流程如下:

1)WebApplicationContext 被绑定到请求中,处理器及其他元素可以访问它。

2)Locale解析器被绑定到请求中,在解析请求时使用。

3)主题解析器被绑定到请求中,让视图等元素确定要使用的主题。

4)如果定义了文件解析器,会检查请求是否有文件,是则会把请求包装为MultipartHttpServletRequest。

5)找到一个合适的解析器,与处理程序关联的执行器会被执行。准备模型或渲染。可以呈现响应或返回视图。

2 基本组件

DispatcherServlet 通过代理模式来代理特殊的组件用以处理请求及渲染合适的响应。

2.1 HandlerInterception 拦截器

HandlerMapping 根据当前请求来找的对应的Handler。并与一系列的HandlerInterceptor封装到HandlerExecutionChain对象中。这个过程发生在容器启动的过程中。

当请求到达前端控制器(DispatcherServlet)时,DispatcherServlet会从容器取出所有的HandlerMapping实例并遍历,每个HandlerMapping 实例都会根据请求的信息(如URL、请求方法等)来确定对应的Handler(通常是Controller的一个方法)。

图 HandlerInterceptor 接口UML

preHandle 如果返回false,则其接下来的处理链都不会被执行。

2.2 HandlerExceptionResolver 异常解析器

处理在处理器方法执行过程中抛出的异常,不会处理拦截器中preHandle抛出的异常。

可以定义多个异常解析器来组成一条解析链。可以设置它们的优先级,其返回值有如下情况:

1)指向错误视图的ModelAndView。

2)如果处理了异常,则返回空的ModelAndView。

3)如果异常未解析,则返回null,供后续解析器尝试,最终可能会冒泡到Servlet容器。

@Configuration
public class CustomExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 设置响应内容类型为JSON
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        Map<String, Object> errorDetails = new HashMap<>();
        errorDetails.put("message", ex.getMessage());
        try {
            response.getWriter().write(errorDetails.toString());
            response.getWriter().flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ModelAndView();
    }
}

2.3 LocaleResolver 区域解析器

Spring 容器可以实现国际化,通过LocaleResolver 来获取区域信息。

时区解析

LocaleContextResolver 扩展了该接口,包括了时区信息。

请求头解析

检查请求中的accept-language头部字段来获取区域信息。但该解析器不包含时区信息。

Cookie解析

检测Cookie中是否有区域与时区信息,需要在解析器中指出该cookie的属性名。过期时间(可选)

Session解析

从用户会话中检索区域和时区信息。这些信息是临时存储在HttpSession中的,会话结束时,信息会丢失。与外部会话管理机制(如Spring Session)没有直接关联。

区域拦截器

可以定义拦截器来设置区域信息。

表 LocaleResolver 的种类

2.4 MultipartResolver 文件解析器

如果设置了文件解析器(默认为空),DispatcherServlet 会检查请求是否带有文件,是,则会将请求包装为MultipartHttpServletRequest。其实现主要有两种:

CommonMultipartResolver: 是Spring在Apache Commons FileUpload组件的基础上封装而来的。允许进行更详细的配置。需要额外的依赖和配置。

StandardServletMultipartResolver: 是基于Servlet 3.0 规范来处理multipart请求。不需要额外的依赖,但要求使用支持Servlet3.0的容器。

public class CustomWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{RootAnnotationConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{ServletAnnotationConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }

    @Override
    protected void customizeRegistration(ServletRegistration.Dynamic registration) {
        MultipartConfigElement element = new MultipartConfigElement("");
        registration.setMultipartConfig(element);
    }
}

http://www.niftyadmin.cn/n/5431058.html

相关文章

创建队列链表(C#、java)

文章目录 1、创建队列2、队列节点3、程序入口 1、创建队列 namespace Testmain {public class StackQueue{QNode Front new QNode(-1);QNode Rear new QNode(-1);QNode curNode;public StackQueue(int data){curNode new QNode(data);if (Front.next null){Front.next cu…

微信小程序-webview分享

项目背景 最近有个讨论区项目需要补充分享功能&#xff0c;希望可以支持在微信小程序进行分享&#xff0c;讨论区是基于react的h5项目&#xff0c;在小程序中是使用we-view进行承载的 可行性 目标是在打开web-view的页面进行分享&#xff0c;那就需要涉及h5和小程序的通讯问…

ASP.NET-WebFoms常见前后端交互方式

在 ASP.NET Web Forms 中&#xff0c;实现前后端交互是开发 Web 应用程序的重要部分。通过合适的数据传递方式&#xff0c;前端页面能够与后端进行有效的通信&#xff0c;并实现数据的传递、处理和展示。本文介绍了ASP.NET Web Forms开发中常见的前后端交互方式&#xff0c;包括…

什么是去中心化,如何去中心化

去中心化&#xff08;Decentralization&#xff09;是指在组织、管理或运作中减少或消除中心化机构或权力的控制和影响&#xff0c;使得决策和资源分配更加分散和民主化的一种管理模式。在数字化和信息化时代&#xff0c;去中心化成为了一个重要的概念&#xff0c;尤其在区块链…

SpringCloud Stream 消息驱动

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第九篇&#xff0c;即介绍 Stream 消息驱动。 二、消息驱动概念 2.1 消息驱动是什么 官方定义 Spring …

前端 - 让多个块级元素div在同一行显示的3种方式

【需求说明】 <div>元素是块级元素,默认它们会自动换行. 如果要想是多个div在同一行中,方法有如下几个: 方法1:使用浮动float属性 - float:left; 创建了一个名为.inline-div的CSS类,设置float: left;属性,以及其他自定义属性。 然后,我们将这个…

PyTorch学习笔记之基础函数篇(九)

统计运算 5.1 torch.mean()函数 torch.mean() 是 PyTorch 中的一个函数&#xff0c;用于计算张量&#xff08;Tensor&#xff09;的平均值。你可以用它来计算一个张量所有元素的平均值&#xff0c;或者指定某个维度上的平均值。 torch.mean() 函数在 PyTorch 中的签名如下&a…

安卓性能优化面试题 16-20

16. Android中的图片优化方案?首先我们可以对图片进行二次采样,从本质上减少图片的内存占用。 就是将大图片缩小之后放入到内存中,以实现减小内存的目的其次就是采用三层缓存架构,提高图片的访问速度。 三层缓存架构是内存-文件-网络。 内存是访问速度最快的部分但是分配的…