SpringMVC源码:DispatcherServlet的初始化(三)

上一部分,FrameworkServlet 将 onRefresh 留给了 DispatcherServlet 来完成,

所以进入 DispatcherServlet # onRefresh

刷新Spring容器(这里刷新的是子容器)

@Override
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);  //这里的参数context,即是之前创建的SpringWeb容器(之后又作为参数,传递给了每个组件的初始化函数)
}

初始化九大组件:initStrategies()

初始化了以下9个组件。SpringMVC正是依赖它们来完成的整个请求处理流程。在后面会详细解析

protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
}

DispatcherServlet 中的重要组件:

private MultipartResolver multipartResolver;  //文件上传
private LocaleResolver localeResolver;
private ThemeResolver themeResolver;
private List<HandlerMapping> handlerMappings;  //处理器映射器
private List<HandlerAdapter> handlerAdapters;  //处理器适配器
private List<HandlerExceptionResolver> handlerExceptionResolvers; //异常处理器
private RequestToViewNameTranslator viewNameTranslator;
private FlashMapManager flashMapManager;  //快照
private List<ViewResolver> viewResolvers;  //视图解析器

上面的组件,它们十分重要,是整个 SpringMVC 工作的核心。这里先介绍它们的初始化(怎么被设置值的),后续再分析每个组件的是负责干啥的。

举例:处理器映射器 HandlerMapping 组件的初始化:initHandlerMappings()

private void initHandlerMappings(ApplicationContext context) {
    
    this.handlerMappings = null;

    // 这个if-else的逻辑:是从 SpringWeb 容器中查找 HandlerMapping ,包括在父容器中的也会查找。
    // 如果,我们在xml中配置了一个HandlerMapping,或者配置了<mvc:annotation-driven/>,那么就会在容器中找到。不再进入后面的 "默认策略" 逻辑
    if (this.detectAllHandlerMappings) {
        Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }else {
        try {
            HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);  //getBean()方法的逻辑,会从父容器中找....
            this.handlerMappings = Collections.singletonList(hm);
        }//...
    }

    // 如果没有找到,则使用默认注册的 HandlerMapping (至少要确保有一个HandlerMapping能拿来用)
    if (this.handlerMappings == null) {
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
        //...
    }
}

默认的组件注册策略(默认配置,策略模式):(相当于一个适配方法:initHandlerMappings()、initHandlerAdapters()、…都会被适配到此处)

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    String key = strategyInterface.getName(); // key 为 HandlerMapping.clss(传过来的也可能是:HandlerAdapter.class、ViewResolver.class、...)
    String value = defaultStrategies.getProperty(key);  // 从外部 defaultStrategies 处获取
    if (value != null) {
        String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
        List<T> strategies = new ArrayList<>(classNames.length);
        for (String className : classNames) {
            try {
                Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
                Object strategy = createDefaultStrategy(context, clazz);   // 创建 HandlerMapping 对象
                strategies.add((T) strategy);  // 加入集合
            }//...
        }
        return strategies;
    }
    else {
        return new LinkedList<>();
    }
}

此处的 defaultStrategies 由外部properties文件所决定,defaultStrategies 在 DispatcherServlet 类的静态代码块中被赋值:

private static final Properties defaultStrategies;

static {
       // 从properties文件中载入默认的初始化接口(开发人员不能自定义properties文件)
       try {
           ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);  // 从"DispatcherServlet.properties"处加载
           defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
       }//...
   }

DispatcherServlet.properties 文件内容(文件位于源码 DispatcherServlet.class 同级目录下)

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
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.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.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.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

可以看到,这里确实定义了不同组件的类型,一共定义了8个组件,处理上传组件MutpartResolver是没有默认配置的,这也很容易理解,并不是每个应用都需要上传功能,即使需要上传也不一定就要使用MultipartResolver,所以MultipartResolver不需要默认配置。另外HandlerMapping、HandlerAdapter和HandlerExceptionResolver都配置了多个,其实View-Resolver也可以有多个,只是默认的配置只有一个。

这里需要注意的是:

默认配置并不是最优配置,也不是spring的推荐配置,只是在没有配置的时候可以有个默认值,不至于空着。

默认配置是在相应的组件没有在springmvc.xml中配置时,才会使用。例如,我们在springmvc.xml中配置了HandlerMapping组件:

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>

那么就会使用这个 BeanNameUrlHandlerMapping 来作为HandlerMapping组件,默认的配置不再生效。(不再会有默认配置中的RequestMappingHandlerMapping了)

另外,当使用了 “< mvc:annotation-driven/>” 后,也并不会全部使用默认配置。因为它配置了HandlerMapping、HandlerAdapter和Handler-ExceptionResolver,而且还做了很多别的工作,更详细的内容可以查看 org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser( 底层是向Spring容器中添加BeanDefinition )

总结:

通过此阶段,DispatcherServlet 初始化了内部的9个组件(若没有在容器中配置这些组件,则会默认从外部文件 “DispatcherServlet.properties” 处决定初始化策略)

DispatcherServlet 在后续请求处理的过程中,会频繁依赖这些组件来完成整个请求服务。

参考书籍《看透 SpringMVC 源代码分析与实践》

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值