【Spring MVC研究】注册Spring MVC中的9个特殊组件到DispatcherServlet属性中。

背景:Spring MVC是一种MVC框架,是Servlet规范的一种实现。Servlet规范定义了很多组件,与日常开发息息相关有2大分支:

  • Servlet分支
  • Filter分支

本文讨论的是Servlet组件,在Spring MVC中核心的Servlet是DispatcherServlet,在DispatcherServlet中有且仅仅初始化了9个特殊的组件,注意是有且仅有

注意:您可能在Spring Boot中听到诸如“欢迎页”、“静态资源”之类的Bean,其中很多其实都是被“组装到了这个9个特殊组件”中

0. Spring MVC的工作原理简述

原理简述:

1、无论是MVC还是Spring Boot,都是通过向容器中注册Bean;

2、容器启动后会引导DispatcherServlet的初始化,初始化时会把相关Bean设置到DispatcherServlet的属性中;

3、最后通过DispatcherServlet中的各种属性Bean处理浏览器的请求。

详细的参考:

1. Spring MVC中的9个特殊组件

DispatcherServlet委托特殊的bean来处理请求并呈现适当的响应。所谓“特殊bean”,我们指的是由spring管理的、实现WebFlux框架契约的对象实例。它们通常带有内置契约,但您可以自定义它们的属性、扩展或替换它们

下表列出了一些常见的特殊bean:

Bean type描述
HandlerMapping映射一个request到handler上(handler也包含一系列的前置和后置拦截器)。映射是基于各种HandlerMapping接口实现。
HandlerAdapterHandlerAdapter的主要目的是保护DispatcherServlet不受这些细节的影
HandlerExceptionResolver处理异常解析器
ViewResolver视图解析器(如果是前后端分离项目直接忽略该部分)
LocaleResolver, LocaleContextResolver
ThemeResolver
MultipartResolver文件上传解析器
FlashMapManager

2. 9个组件的注册原理

  • 因为DispatcherServlet也是Servlet,根据Servlet规范会调用Servlet的public void init(ServletConfig config) throws ServletException;,最后会调用到DispatcherServlet的初始化会加载如下的代码。

下面代码就是用来初始化DispatcherServlet的9种特殊bean。

// 负责初始化以上各个组件
protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context); //
    initThemeResolver(context);
    initHandlerMappings(context);//
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
}
  • 以上9个组件的初始化,除了MultipartResolver,其他组件如果用户没有自定义则会从DispatcherServlet.properties加载默认的配置

MultipartResolver太特殊了,默认没有配置,也就是说Spring MVC默认是不支持”文件上传“

  • DispatcherServlet.properties文件内容
# 刚好是8个组件(除了没有MultipartResolver)
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
	org.springframework.web.servlet.function.support.RouterFunctionMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
	org.springframework.web.servlet.function.support.HandlerFunctionAdapter


org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashM

3. 对Spring MVC注册组件的质疑

在DispatcherServlet的protected void initStrategies(ApplicationContext context)方法中。注册了Spring MVC的特殊组件,但是对于几个List类型的组件,自定义的时候使用了Spring的排序规则AnnotationAwareOrderComparator,而对从DispatcherServlet.properties加载的配置没有应用排序规则,是否应该认为Spring没有提供统一的排序方式呢?

以initHandlerMappings()方法为例:

private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;
 
        Map<String, HandlerMapping> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            // <1> 从容器中获取的bean就应用了排序规则
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
 
 
    if (this.handlerMappings == null) {
        // <2> 针对从DispatcherServlet.properties加载的配置没有应用排序规则
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                         "': using default strategies from DispatcherServlet.properties");
        }
    }
}

3. 参考

官网:https://docs.spring.io/spring-framework/docs/5.0.6.RELEASE/spring-framework-reference/web.html#mvc-servlet-special-bean-types

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fire Fish

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值