[SpringMVC]初始化HandlerMapping、HandlerAdapter

背景

初始化整体流程文章中,只是介绍了流程,并且没有对各个组件的初始化以及请求流程做详细的介绍,本章主要是介绍下初始化的流程:

详细介绍

整体初始化过程

在DispatcherServlet的initStrategies初始了Springmvc的9大组件:

   /**
     * 初始化此servlet使用的策略对象。
     * 以便初始化进一步的策略对象
     * Initialize the strategy objects that this servlet uses.
     * <p>May be overridden in subclasses in order to initialize further strategy objects.
     */
    protected void initStrategies(ApplicationContext context) {
        // 初始化MultipartResolver 用来处理上传文件 默认是没有处理的,需要在上下文添加MultipartResolver处理器
        //  org.springframework.web.multipart.commons.CommonsMultipartResolver
        // org.springframework.web.multipart.support.ByteArrayMultipartFileEditor
        //  org.springframework.web.multipart.support.StringMultipartFileEditor
        initMultipartResolver(context);
        // 初始化LocaleResolver 配置国际化的
        initLocaleResolver(context);
        // 初始化ThemeResolver 通过主题控制页面风格
        initThemeResolver(context);
        // 初始化HandlerMappings  由定义请求和处理程序对象之间映射的对象实现
        initHandlerMappings(context);
        // 初始化HandlerAdapters
        initHandlerAdapters(context);
        // 初始化HandlerExceptionResolvers 异常处理
        initHandlerExceptionResolvers(context);
        // 初始化RequestToViewNameTranslator
        initRequestToViewNameTranslator(context);
        // 初始化ViewResolvers
        initViewResolvers(context);
        // 初始化FlashMapManager
        initFlashMapManager(context);
    }

初始化HandleMapping

HandlerMapping是什么?

定义请求和处理程序对象之间的映射.这个类可以由开发人员实现,框架已经开发了org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping和org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping。如果在应用程序上下文中没有注册HandlerMapping bean,则前者是默认值。
HandlerMapping实现可以支持映射的拦截器

/**
     * 初始化 HandlerMappings.
     * <p>如果没有在命名空间定义,则默认使用BeanNameUrlHandlerMapping.
     */
    private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;

        if (this.detectAllHandlerMappings) {
            // 查找ApplicationContext中的所有HandlerMappings,包括父上下文
            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);
                this.handlerMappings = Collections.singletonList(hm);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerMapping later.
            }
        }

        // 通过注册确保我们至少有一个HandlerMapping
 如果找不到其他映射,则使用默认的HandlerMapping
        if (this.handlerMappings == null) {
            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
            if (logger.isDebugEnabled()) {
                logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
            }
        }
    }

这个简单吧,下面看下HandlerAdapter的初始化。理解了上面的,HandlerAdapter就很简单了

HandlerAdapter

HandlerAdapter是什么?

MVC框架SPI,允许参数化核心MVC工作流程,每个处理类的适配接口

 /**
     * 初始化.
     * <p>if 不存在 则用 SimpleControllerHandlerAdapter.
     */
    private void initHandlerAdapters(ApplicationContext context) {
        this.handlerAdapters = null;

        if (this.detectAllHandlerAdapters) {
            // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
            Map<String, HandlerAdapter> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
                // We keep HandlerAdapters in sorted order.
                OrderComparator.sort(this.handlerAdapters);
            }
        } else {
            try {
                HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
                this.handlerAdapters = Collections.singletonList(ha);
            } catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerAdapter later.
            }
        }

        // Ensure we have at least some HandlerAdapters, by registering
        // default HandlerAdapters if no other adapters are found.
        if (this.handlerAdapters == null) {
            this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
            if (logger.isDebugEnabled()) {
                logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
            }
        }
    }

总结

这个两个方法流程上基本上相同,主要用到了两个静态方法

BeanFactoryUtils#beansOfTypeIncludingAncestors

根据给定的类型或者子类类型返回所有bean
如果当前的bean工厂是HierarchicalBeanFactory,也会获取在祖先bean工厂中定义的bean
递归获取

Spring提供了很多工具类很好用,我们平常开发过程中,不用再重复造轮子,不过最好知道Spring的内部实现,比如:BeanFactoryUtils、AnnotationUtils、ClassUtils、BeanUtils、ReflectionUtils、ResourceUtils等

DispatcherServlet#getDefaultStrategies

创建一个给定的策略接口的默认策略对象
1、根据参数strategyInterface从DispatcherServlet.properties文件查询(提前初始化好)对象的类列表
2、通过Class.forName实例化

其他

其他Springmvc的组件初始化流程基本一样

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容