SpringMVC核心组件之(HandlerAdapter)

19 篇文章 5 订阅
4 篇文章 1 订阅

url映射(HandlerMapping)的执行适配器

DispatcherServlet类中的initHandlerAdapters()初始化handlerAdapters

SpringMVC默认有三个

  1. HttpRequestHandlerAdapter, 该HttpRequestHandler接口的适配执行器
  2. SimpleControllerHandlerAdapter, 该Controller接口的适配执行器
  3. RequestMappingHandlerAdapter,处理@RequestMapping的适配执行器

先看看代码块,如果需要自定义,尽量将默认的也注入到容器中

public class DispatcherServlet extends FrameworkServlet {
    private void initHandlerAdapters(ApplicationContext context) {
        this.handlerAdapters = null;

        if (this.detectAllHandlerAdapters) {
            // 查找容器中所有的 HandlerAdapter类型的Bean
            Map<String, HandlerAdapter> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerAdapters = new ArrayList<>(matchingBeans.values());
                // 排序
                AnnotationAwareOrderComparator.sort(this.handlerAdapters);
            }
        }
        else {
            try {
                /* 只从容器中获取 BeanName = handlerAdapter  HandlerAdapter类型的Bean */
                HandlerAdapter ha = context.getBean("handlerAdapter", HandlerAdapter.class);
                this.handlerAdapters = Collections.singletonList(ha);
            }
            catch (NoSuchBeanDefinitionException ex) {
            }
        }
        /**
         * 没有自定义 使用默认的
         */
        if (this.handlerAdapters == null) {
            this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
        }
    }
}
getDefaultStrategies(context, Class)

根据Class类型创建默认的实例,依靠Web容器的createBean创建实例

defaultStrategies 这里有一个静态变量,保存着SpringMVC的默认配置,查看默认配置文件

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
        String key = strategyInterface.getName();
        /**
         * 重点关注下这里 SpringMVC 的默认策略
         */
        String value = defaultStrategies.getProperty(key);
        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());
                    /**
                     * 这里是用 Web容器去创建实例
                     * 默认是多实例的(scope = provided)
                     */
                    Object strategy = createDefaultStrategy(context, clazz);
                    strategies.add((T) strategy);
                }
                catch (ClassNotFoundException ex) {
                }
                catch (LinkageError err) {
                }
            }
            return strategies;
        }
        else {
            return new LinkedList<>();
        }
    }

createDefaultStrategy(context, clazz)

调用 Web容器的createBean创建Bean


1:HttpRequestHandlerAdapter

处理 HttpRequestHandler接口的 url映射

public class HttpRequestHandlerAdapter implements HandlerAdapter {
    /**
     * 是否支持该 handler 执行 ( 判断 handler 是否是 实现了 HttpRequestHandler接口)
     * @param handler
     * @return 返回true 代表应用该适配器执行url映射处理
     */
    @Override
    public boolean supports(Object handler) {
        return (handler instanceof HttpRequestHandler);
    }
    /**
     * 执行 {@link HttpRequestHandler#handleRequest(HttpServletRequest, HttpServletResponse)}
     */
    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        ((HttpRequestHandler) handler).handleRequest(request, response);
        return null;
    }
    /**
     * 获取上次修改
     * @return
     */
    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        if (handler instanceof LastModified) {
            return ((LastModified) handler).getLastModified(request);
        }
        return -1L;
    }
}

2:SimpleControllerHandlerAdapter

处理 Controller接口的 url映射

public class SimpleControllerHandlerAdapter implements HandlerAdapter {
    /**
     * 是否支持该 handler 执行  ( 判断 handler 是否是 实现了 Controller接口)
     * @return 返回true 代表应用该适配器执行url映射处理
     */
    @Override
    public boolean supports(Object handler) {
        return (handler instanceof Controller);
    }
    /**
     * 执行 {@link Controller#handleRequest(HttpServletRequest, HttpServletResponse)}
     */
    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return ((Controller) handler).handleRequest(request, response);
    }
    /**
     * 获取上次修改
     * @return
     */
    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        if (handler instanceof LastModified) {
            return ((LastModified) handler).getLastModified(request);
        }
        return -1L;
    }
}

3:RequestMappingHandlerAdapter

处理 @RequestMapping接口的 url映射 最为常用的

一个请求通过 RequestMappingHandlerAdapter 执行的大致过程。
1:通过请求的url获取执行目标方法(HandlerMapping)。
2:通过(HandlerMapping)获取到适配的HandlerAdapter,此处是(RequestMappingHandlerAdapter)。
3:通过目标方法参数类型,获取适配的参数解析器(HandlerMethodArgumentResolver),进行参数赋值。
4:通过目标方法的返回值类型,获取到适配的返回数据处理器(HandlerMethodReturnValueHandler)
5:通过返回数据类型获取到适配的消息转换器(HttpMessageConverter),响应数据。

在这里插入图片描述


底层源码分析
重点关注它实现的afterPropertiesSet接口下的Bean实例化成功的初始化方法。
在这里插入图片描述
说明:此处就不以SpringMVC在DispatcherServlet.initHandlerAdapters方法初始化HandlerAdapter分析了,因为我们开发中都是用SpringBoot(自动装配版开发的)。

直接看到@EnableWebMvc注解中导入的类DelegatingWebMvcConfiguration的父类WebMvcConfigurationSupport
在这里插入图片描述
在这里插入图片描述

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {

    /**
     * 向容器注入一个 Bean    @Bean
     * @return
     */
    @Bean
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
        /**
         * 创建 RequestMappingHandlerAdapter 实例
         * new RequestMappingHandlerAdapter()
         */
        RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
        adapter.setContentNegotiationManager(mvcContentNegotiationManager());
        /**
         * 设置 消息转换器(MessageConverters)
         */
        adapter.setMessageConverters(getMessageConverters());
        adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
        /**
         * 设置自定义的 参数解析器(ArgumentResolver)
         * {@link WebMvcConfigurer#addArgumentResolvers(List)}
         */
        adapter.setCustomArgumentResolvers(getArgumentResolvers());
        /**
         * 设置自定义的 返回值处理器(ReturnValueHandler)
         * {@link WebMvcConfigurer#addReturnValueHandlers(List)}
         */
        adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

        if (jackson2Present) {
            adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
            adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
        }

        /**
         * 以下是 异步支持
         */
        AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
        configureAsyncSupport(configurer);
        if (configurer.getTaskExecutor() != null) {
            adapter.setTaskExecutor(configurer.getTaskExecutor());
        }
        if (configurer.getTimeout() != null) {
            adapter.setAsyncRequestTimeout(configurer.getTimeout());
        }
        /**
         * {@link Callable}
         */
        adapter.setCallableInterceptors(configurer.getCallableInterceptors());
        /**
         * {@link DeferredResult}
         */
        adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

        return adapter;
    }
}

关注下adapter.setMessageConverters(getMessageConverters())获取消息转换器,然后赋值,这里面有点东西。

一开始使用 我们配置的WebMvcConfigurer.configureMessageConverters
如果它不返回空,则直接应用这些消息转换器,不再使用默认的消息转换器
我们可以基于这一点,直接定制化SpringMVC的消息转换器。
如果只是想添加一个消息转换器,则使用WebMvcConfigurer.extendMessageConverters

再说下,如果没有必要,请勿使用WebMvcConfigurer.configureMessageConverters该配置,经量使用SpringMVC默认的配置项。

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
    protected final List<HttpMessageConverter<?>> getMessageConverters() {
        /* 一开始创建 肯定为 null */
        if (this.messageConverters == null) {
            this.messageConverters = new ArrayList<>();
            /**
             * 这里是调用
             * {@link WebMvcConfigurer#configureMessageConverters(List)}
             */
            configureMessageConverters(this.messageConverters);

            if (this.messageConverters.isEmpty()) {
                /* 如果为空 使用默认的 */
                addDefaultHttpMessageConverters(this.messageConverters);
            }
            /**
             * 这里是调用  拓展WebMvcConfigurer
             * {@link WebMvcConfigurer#extendMessageConverters(List)}
             */
            extendMessageConverters(this.messageConverters);
        }
        return this.messageConverters;
    }
}

RequestMappingHandlerAdapter.afterPropertiesSet Bean实例化初始化方法,参数解析,返回值解析,都有各自的包装类。

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
        implements BeanFactoryAware, InitializingBean {
    @Override
    public void afterPropertiesSet() {
        /**
         * 初始化 @ControllerAdvice 缓存
         * 从容器中获取 所有 @ControllerAdvice 的Bean 缓存到当前实例中
         */
        initControllerAdviceCache();

        /**
         * 参数解析器赋值
         */
        if (this.argumentResolvers == null) {
            /**
             * 获取默认的 和 自定义的
             */
            List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
            /* 包装下 */
            this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }

        if (this.initBinderArgumentResolvers == null) {
            List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
            this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }

        /**
         * 返回值处理器赋值
         */
        if (this.returnValueHandlers == null) {
            /**
             * 获取默认的 和 自定义的
             */
            List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
            /* 包装下 */
            this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
        }
    }
}

在SpringBoot中,SpringMVC是这样子装配的,在WebMvcAutoConfiguration内部类EnableWebMvcConfiguration
所在目录包 org.springframework.boot.autoconfigure.web.servlet

在这里插入图片描述


总结

RequestMappingHandlerAdapter最终都是Spring容器创建的实例,而且它提供了很多set方法,我们可以在开发中,通过applicationContext获取到此Bean,动态的修改它的属性。
例如:

  • 删除掉它一些默认的参数解析器,消息转换器之类的。
  • 因为它的解析器,处理器都是List列表,我们可以将我们自定义的添加到他的前面。
  • 比如@RequestParam注解,为空报错提示修改。
  • 最重要的就是,要深入理解SpringMVC的源码,我们就可以定制化SpringMVC。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Me_Liu_Q

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

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

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

打赏作者

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

抵扣说明:

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

余额充值