探索SpringMVC(二)--DispatcherSevlet的默认依赖Beans

上一节谈到DispatcherServlet默认做了很多事情,默认的依赖Beans
本节探索具体的Beans
结论:

使用如下配置+DispatcherServlet进行SpringMVC的使用时

<mvc:annotation-driven ></mvc:annotation-driven>

DispatcherServlet默认依赖的Bean有

DispatcherServlet在通常使用情况下的默认引用(依赖)Beans
依赖的Beans复数?存在默认配置值?装配方式名称或类型具体实现类
MutipartResolvernono名称multipartResolver
LocaleResolvernoyes名称localeResolverorg.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
ThemeResolvernoyes名称themeResolverorg.springframework.web.servlet.theme.FixedThemeResolver
RequestToViewNameTranslatornoyes名称viewNameTranslatororg.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
FlashManagernoyes名称flashManagerorg.springframework.web.servlet.support.SessionFlashMapManager
HandlerMappingsyesyes类型HandlerMapping org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
HandlerAdaptersyesyes类型HandlerAdapter org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
HadnlerExceptionResolversyesyes类型HadnlerExceptionResolver org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
ViewResolversyesyes类型ViewResolver org.springframework.web.servlet.view.InternalResourceViewResolver


测试发现,当我们使用<mvc:annotation-driven >进行简单配置时,实际IOC容器中是重新定义了HandlerMappings、HandlerAdapters、HadnlerExceptionResolvers其他则是使用DispatherServlet.properties的默认配置。

也就是说<mvc:annotation-driven ></mvc:annotation-driven >,实际就是配置了HanleMappings、HandleMappingAdapters、HadnlerExceptionResolvers.

DispatcherServlet默认依赖的相关Beans一览

  • =========================重点 BEGIN=====================
  • HandlerMapping
    • 将传入的请求映射到处理程序和一个列表的前和后处理器(处理程序拦截器)基于某些标准随HandlerMapping实现的细节。【连接请求(request)与处理器+(前置、后置)拦截器的作用】
  • HandlerAdapter
    • 帮助DispatcherServlet去调用一个被请求映射的Handler,无论这个Handler是否会被真正的调用【适配Handler与HandlerMapping
  • HandlerExceptionResolver
    • Handler异常解析器
  • ViewResolver
    • 视图解析器
  • LocaleResolver & LocaleContextResolver
    • 本地化相关解析器
  • =========================重点 END=====================
  • ThemeResolver
    • 主题解析器
  • MultipartResolver
    • mutipart解析器【应该是和文件上传有关吧,猜测】
  • FlashMapManager
    • Flash相关?

    DispatcherServlet源码中

    /** MultipartResolver used by this servlet */
        private MultipartResolver multipartResolver;
    
        /** LocaleResolver used by this servlet */
        private LocaleResolver localeResolver;
    
        /** ThemeResolver used by this servlet */
        private ThemeResolver themeResolver;
    
        /** List of HandlerMappings used by this servlet */
        private List<HandlerMapping> handlerMappings;
    
        /** List of HandlerAdapters used by this servlet */
        private List<HandlerAdapter> handlerAdapters;
    
        /** List of HandlerExceptionResolvers used by this servlet */
        private List<HandlerExceptionResolver> handlerExceptionResolvers;
    
        /** RequestToViewNameTranslator used by this servlet */
        private RequestToViewNameTranslator viewNameTranslator;
    
        /** FlashMapManager used by this servlet */
        private FlashMapManager flashMapManager;
    
        /** List of ViewResolvers used by this servlet */
        private List<ViewResolver> viewResolvers;
    值得注意的是handlerMappings、handlerAdapters、handlerExceptionResolvers、viewResolvers他们是List,我们可以配置多个。
    **他们的具体实现类一览(取自DispatcherServlet.properties)**
    # 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.annotation.DefaultAnnotationHandlerMapping
    
    org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
        org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
        org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
    
    org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
        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
    大坑:发现DefaultAnnotationHandlerMapping已经被丢弃,由RequestMappingHandlerMapping取代但是在属性文件还是上面的配置
    **DispatcherServlet对请求的处理顺序(官方描述翻译)**
    • The WebApplicationContext is searched for and bound in the request as an attribute that the controller and other elements in the process can use. It is bound by default under the key DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE.
    • The locale resolver is bound to the request to enable elements in the process to resolve the locale to use when processing the request (rendering the view, preparing data, and so on). If you do not need locale resolving, you do not need it.
    • The theme resolver is bound to the request to let elements such as views determine which theme to use. If you do not use themes, you can ignore it.
    • If you specify a multipart file resolver, the request is inspected for multiparts; if multiparts are found, the request is wrapped in a MultipartHttpServletRequest for further processing by other elements in the process. See Section 18.10, “Spring’s multipart (file upload) support” for further information about multipart handling.
    • An appropriate handler is searched for. If a handler is found, the execution chain associated with the handler (preprocessors, postprocessors, and controllers) is executed in order to prepare a model or rendering.
    • If a model is returned, the view is rendered. If no model is returned, (may be due to a preprocessor or postprocessor intercepting the request, perhaps for security reasons), no view is rendered, because the request could already have been fulfilled.
    • 搜索WebApplicationContext并将他绑定到请求Request的属性上,通过默认的名称DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE
    • 绑定local resolver(可选)
    • 绑定theme resolver(可选)
    • 如果指定了一个multipart file resolver,这个请求被检测到multiparts,请求将会包装为MultipartHttpServletRequest 来被其他元素处理。
    • 寻找一个合适的Handler,如果Handler被找到,为了得到一个model或者呈现而去执行相关的链(前置处理器、后置处理器和Controller)。
      如果返回一个model,则视图被呈现,或者没有model返回。

    DispatcherServlet源码分析,SpringMVC到底默认加了哪些Beans为我们服务?

    
        /**
         * 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) {
            initMultipartResolver(context);
            initLocaleResolver(context);
            initThemeResolver(context);
            initHandlerMappings(context);
            initHandlerAdapters(context);
            initHandlerExceptionResolvers(context);
            initRequestToViewNameTranslator(context);
            initViewResolvers(context);
            initFlashMapManager(context);
        }

    initStrategies(ApplicationContext context)
    在DispatcherServlet初始化时候被调用。由上面代码可以看到,在这里初始化了相关Beans。下面进行分析:

    initMultipartResolver(context)//初始化MutipartResolver

    /**
         * Initialize the MultipartResolver used by this class.
         * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
         * no multipart handling is provided.
         */
        private void initMultipartResolver(ApplicationContext context) {
            try {
                this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
                }
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Default is no multipart resolver.
                this.multipartResolver = null;
                if (logger.isDebugEnabled()) {
                    logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
                            "': no multipart request handling provided");
                }
            }
        }

    没有默认的MutipartResolver
    可以通过DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME(multipartResolver)名称在IOC容器中进行配置

    initLocaleResolver(context)//初始化LocaleResolver

    /**
         * Initialize the LocaleResolver used by this class.
         * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
         * we default to AcceptHeaderLocaleResolver.
         */
        private void initLocaleResolver(ApplicationContext context) {
            try {
                this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
                }
            }
            catch (NoSuchBeanDefinitionException ex) {
                // We need to use the default.
                this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
                            "': using default [" + this.localeResolver + "]");
                }
            }
        }

    本地化解析器LocaleResolver是有默认Bean的呦!具体的方法就不再展示给出具体类型:DispatcherServlet.properties中
    key为org.springframework.web.servlet.LocaleResolver(LocaleResolver类全名)的值

    initThemeResolver(context)

    /**
         * Initialize the ThemeResolver used by this class.
         * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
         * we default to a FixedThemeResolver.
         */
        private void initThemeResolver(ApplicationContext context) {
            try {
                this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("Using ThemeResolver [" + this.themeResolver + "]");
                }
            }
            catch (NoSuchBeanDefinitionException ex) {
                // We need to use the default.
                this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("Unable to locate ThemeResolver with name '" + THEME_RESOLVER_BEAN_NAME +
                            "': using default [" + this.themeResolver + "]");
                }
            }
        }

    存在默认Bean,也可以IOC中配置,配置会取代默认。
    IOC配置名称:DispatcherServlet.THEME_RESOLVER_BEAN_NAME(themeResolver)
    默认值:DispatcherServlet.properties中key:ThemeResolver.class全名的配置值

    initRequestToViewNameTranslator(ApplicationContext context)

    /**
         * Initialize the RequestToViewNameTranslator used by this servlet instance.
         * <p>If no implementation is configured then we default to DefaultRequestToViewNameTranslator.
         */
        private void initRequestToViewNameTranslator(ApplicationContext context) {
            try {
                this.viewNameTranslator =
                        context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("Using RequestToViewNameTranslator [" + this.viewNameTranslator + "]");
                }
            }
            catch (NoSuchBeanDefinitionException ex) {
                // We need to use the default.
                this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("Unable to locate RequestToViewNameTranslator with name '" +
                            REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME + "': using default [" + this.viewNameTranslator +
                            "]");
                }
            }
        }

    IOC没有配置ViewTranslator时使用属性文件默认值

    initFlashMapManager(ApplicationContext context)

    /**
         * Initialize the RequestToViewNameTranslator used by this servlet instance.
         * <p>If no implementation is configured then we default to DefaultRequestToViewNameTranslator.
         */
        private void initRequestToViewNameTranslator(ApplicationContext context) {
            try {
                this.viewNameTranslator =
                        context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("Using RequestToViewNameTranslator [" + this.viewNameTranslator + "]");
                }
            }
            catch (NoSuchBeanDefinitionException ex) {
                // We need to use the default.
                this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("Unable to locate RequestToViewNameTranslator with name '" +
                            REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME + "': using default [" + this.viewNameTranslator +
                            "]");
                }
            }
        }

    IOC没有配置FlashMapManager时使用属性文件默认值

    initHandlerMappings(ApplicationContext context)

    /**
         * Initialize the HandlerMappings used by this class.
         * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
         * we default to BeanNameUrlHandlerMapping.
         */
        private void initHandlerMappings(ApplicationContext context) {
            this.handlerMappings = null;
    
            if (this.detectAllHandlerMappings) {
                // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
                Map<String, HandlerMapping> matchingBeans =
                        BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
                if (!matchingBeans.isEmpty()) {
                    this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
                    // We keep HandlerMappings in sorted order.
                    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.
                }
            }

    boolean detectAllHandlerMappings默认为true,检查所有的HandlerMappings
    默认情况下会在IOC容器中,而且是整个IOC容器中,查询所有的HandlerMapping的实现类,并经过Order排序组成一个HandlerMappings的List集合。
    如果设置了detectAllHandlerMappings=false,
    则只在IOC容器中查询名为DispatcherServlet.HANDLER_MAPPING_BEAN_NAME。此时也就是只有一个HandlerMapping。
    注意:为了确保存在HanlerMappings,如果我们设置了detectAllHandlerMappings=false,但是在IOC容器中没有配置名称为handlerMapping的Bean,此时依旧会使用默认配置(即属性文件里的配置)

    initHandlerAdapters(ApplicationContext context)
    initHandlerExceptionResolvers(ApplicationContext context)
    initViewResolvers(ApplicationContext context)

    与handlerMappings类似,不再赘述。附上源码

        /**
         * Initialize the HandlerAdapters used by this class.
         * <p>If no HandlerAdapter beans are defined in the BeanFactory for this namespace,
         * we default to 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.
                    AnnotationAwareOrderComparator.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");
                }
            }
        }
        /**
         * Initialize the HandlerExceptionResolver used by this class.
         * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
         * we default to no exception resolver.
         */
        private void initHandlerExceptionResolvers(ApplicationContext context) {
            this.handlerExceptionResolvers = null;
    
            if (this.detectAllHandlerExceptionResolvers) {
                // Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
                Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
                        .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
                if (!matchingBeans.isEmpty()) {
                    this.handlerExceptionResolvers = new ArrayList<HandlerExceptionResolver>(matchingBeans.values());
                    // We keep HandlerExceptionResolvers in sorted order.
                    AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
                }
            }
            else {
                try {
                    HandlerExceptionResolver her =
                            context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
                    this.handlerExceptionResolvers = Collections.singletonList(her);
                }
                catch (NoSuchBeanDefinitionException ex) {
                    // Ignore, no HandlerExceptionResolver is fine too.
                }
            }
    
            // Ensure we have at least some HandlerExceptionResolvers, by registering
            // default HandlerExceptionResolvers if no other resolvers are found.
            if (this.handlerExceptionResolvers == null) {
                this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default");
                }
            }
        }
    /**
         * Initialize the ViewResolvers used by this class.
         * <p>If no ViewResolver beans are defined in the BeanFactory for this
         * namespace, we default to InternalResourceViewResolver.
         */
        private void initViewResolvers(ApplicationContext context) {
            this.viewResolvers = null;
    
            if (this.detectAllViewResolvers) {
                // Find all ViewResolvers in the ApplicationContext, including ancestor contexts.
                Map<String, ViewResolver> matchingBeans =
                        BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
                if (!matchingBeans.isEmpty()) {
                    this.viewResolvers = new ArrayList<ViewResolver>(matchingBeans.values());
                    // We keep ViewResolvers in sorted order.
                    AnnotationAwareOrderComparator.sort(this.viewResolvers);
                }
            }
            else {
                try {
                    ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
                    this.viewResolvers = Collections.singletonList(vr);
                }
                catch (NoSuchBeanDefinitionException ex) {
                    // Ignore, we'll add a default ViewResolver later.
                }
            }
    
            // Ensure we have at least one ViewResolver, by registering
            // a default ViewResolver if no other resolvers are found.
            if (this.viewResolvers == null) {
                this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default");
                }
            }
        }
    • 0
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论

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

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

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值