SpringMVC的处理器适配器-HandlerAdapter的用法及说明

 更新时间:2023年12月26日 15:02:40   作者:huangyaa729  
这篇文章主要介绍了SpringMVC的处理器适配器-HandlerAdapter的用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

SpringMVC处理器适配器HandlerAdapter用法

如题:

今天看spring源码解析这本书时,看到了这个地方,对于不同HandlerAdapter的使用场景有的困惑,主要还是没见过,因为大多数面向的Controller类型的HandlerAdapter;

HandlerAdapter目前最常见的主要为

1、SimpleControllerHandlerAdapter、HttpRequestHandlerAdapter 、AnnotationMethodHandlerAdapter (已过时),这三个是默认的;如果没有指明新的适配器时,会从这三个中间选择;

2、SimpleServletHandlerAdapter目前很少用到,也不是默认的适配器;

3、RequestMappingHandlerAdapter这个应该是目前springMVC主要采用的,针对方法级的映射匹配处理。

由HandlerAdapter的实现类可知:映射匹配的处理器handler包括三个类型Controller、HttpRequestHandler、Servlet,但后两个的应用场景与使用方式我却没有见到过,经过一番查找,特做一个总结以供以后参考:

1、SimpleControllerHandlerAdapter主要是针对实现Controller接口的handler进行适配,配置方式在书中可见;

2、SimpleServletHandlerAdapter主要是针对实现Servlet接口的handler进行适配,配置方式跟普通的Controller类似,如下所示:

spring配置文件中bean的配置如下:

/** 采用BeanNameUrlHandlerMapping类进行路径映射匹配**/
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
 <bean name="/demo.do" class="com.demo.DemoServlet"/>  

对应的Bean实现类为

public class DemoServlet extends HttpServlet{  
.......
}

3、HttpRequestHandlerAdapter 主要是针对实现HttpRequestHandler接口的handler进行适配;

HTTP请求处理器适配器仅仅支持对HTTP请求处理器的适配。它简单的将HTTP请求对象和响应对象传递给HTTP请求处理器的实现,它并不需要返回值。它主要应用在基于HTTP的远程调用的实现上。

配置应该与上述相同,从SpringMvc自带的实现类来说,主要用于转发或者静态资源的加载,对应的实现类为DefaultServletHttpRequestHandler和ResourceHttpRequestHandler

浅谈HandlerAdapter

HandlerAdapter顾名思义就是一个适配器,(肯定也采用了适配器模式这里不做过多的解释),那么它的主要作用是什么呢?

HandlerMapping存储了所有都请求映射,请求过来找到相应的请求映射后,返回给我们一个Handler

看这里的代码:

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        Iterator var2 = this.handlerMappings.iterator();

        while(var2.hasNext()) {
            HandlerMapping mapping = (HandlerMapping)var2.next();
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }

    return null;
}

这里是DispacherServlet的核心控制方法。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 
        try {
            try {
                ModelAndView mv = null;
                Object dispatchException = null;
 
                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }
 
                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = HttpMethod.GET.matches(method);
                    if (isGet || HttpMethod.HEAD.matches(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }
 
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
 
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
 
                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }
 
                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }
 
        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }
 
        }
    }

我们拿到Handler之后呢?

接着代码往下走我们可以看到这样一行代码

HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());

这一步就是讲我们的Handler进行一个HandlerAdapter的适配解析,我们继续代码跟进

public interface HandlerAdapter {
    //如果当前支持当前handler就执行handler方法
    boolean supports(Object handler);
 
    @Nullable
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
 
    /** @deprecated */
    @Deprecated
    long getLastModified(HttpServletRequest request, Object handler);
}

我们知道它采用的适配器模式

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        Iterator var2 = this.handlerAdapters.iterator();

        while(var2.hasNext()) {
            HandlerAdapter adapter = (HandlerAdapter)var2.next();
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }

    throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

DispacherServlet中这个方法,就是一个迭代器,给handler找一个适配器,那这一步到底是要做什么呢?

在HandlerAdapter中有四个实现类,分别处理不同Handler我们看一下我们最常用的HttpRequestHandlerAdapter

public boolean supports(Object handler) {
    return handler instanceof HttpRequestHandler;
}

里面就是去判断了,当前handler是不是HttpRequestHandler类型,其实在我们确认号类型的时候,handler经过RequestMappingHandlerMapping​,返回的就已经是这个类型的了。

找到适配器之后啊,就是开始参数解析了

String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
if (isGet || HttpMethod.HEAD.matches(method)) {
    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
    if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
        return;
    }
}

核心在这里,利用的HandlerAdapter,也就是刚才找到的适配器,和目标方法传进去,执行目标方法。​

执行完上面代码,就是判断了一下是不是get请求,HEAD这个不是由我们 去处理的。

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

上面这行代码去执行的目标方法。

到这里基本是完成了HandlerAdapter的一个准备工作,找到适配的HandlerAdapter之后,还要进行相应的参数解析啊。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 全方位解析key值不确定的json数据

    全方位解析key值不确定的json数据

    这篇文章主要介绍了全方位解析key值不确定的json数据,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • Java Online Exam在线考试系统的实现

    Java Online Exam在线考试系统的实现

    读万卷书不如行万里路,只学书上的理论是远远不够的,只有在实战中才能获得能力的提升,本篇文章手把手带你用java+springboot+vue+jsp+mysql+maven实现Online Exam在线考试系统,大家可以在过程中查缺补漏,提升水平
    2021-11-11
  • 迅速学会@ConfigurationProperties的使用操作

    迅速学会@ConfigurationProperties的使用操作

    这篇文章主要介绍了迅速学会@ConfigurationProperties的使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • java实现微信红包 拼手气红包

    java实现微信红包 拼手气红包

    这篇文章主要为大家详细介绍了java实现微信红包,拼手气红包,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • Springboot详解如何实现SQL注入过滤器过程

    Springboot详解如何实现SQL注入过滤器过程

    这篇文章主要介绍了基于springboot实现SQL注入过滤器,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2022-06-06
  • springcloud中Feign超时提示Read timed out executing POST的问题及解决方法

    springcloud中Feign超时提示Read timed out executing

    Feign接口调用分两层,Ribbon的调用和Hystrix调用,理论上设置Ribbon的时间即可,但是Ribbon的超时时间和Hystrix的超时时间需要结合起来,这篇文章给大家介绍springcloud之Feign超时提示Read timed out executing POST问题及解决方法,感兴趣的朋友一起看看吧
    2024-01-01
  • 分布式服务Dubbo+Zookeeper安全认证实例

    分布式服务Dubbo+Zookeeper安全认证实例

    下面小编就为大家分享一篇分布式服务Dubbo+Zookeeper安全认证实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-12-12
  • Java中的MapStruct知识点总结

    Java中的MapStruct知识点总结

    这篇文章主要介绍了Java中的MapStruct知识点总结,MapStruct是一个Java注解处理器,用于生成类型安全的映射代码,它可以自动处理源对象和目标对象之间的映射,减少了手动编写重复的映射代码的工作量,需要的朋友可以参考下
    2023-10-10
  • 在SpringBoot当中使用Thymeleaf视图解析器的详细教程

    在SpringBoot当中使用Thymeleaf视图解析器的详细教程

    Thymeleaf是一款开源的模板引擎,它允许前端开发者使用HTML与XML编写动态网页,hymeleaf的主要特点是将表达式语言嵌入到HTML结构中,它支持Spring框架,使得在Spring MVC应用中集成非常方便,本文给大家介绍了在SpringBoot当中使用Thymeleaf视图解析器的详细教程
    2024-09-09
  • springboot2.3 整合mybatis-plus 高级功能(图文详解)

    springboot2.3 整合mybatis-plus 高级功能(图文详解)

    这篇文章主要介绍了springboot2.3 整合mybatis-plus 高级功能,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08

最新评论