Spring MVC(一)— DispatcherServlet

 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);
    }
}
  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值