Spring学习总结(2.3)-Spring MVC:handlerAdapter

前面一篇博客介绍了HandlerMapping这个组件,它负责的是定位请求处理器Handler。这是SpringMvc处理流程的第二步。那么,当定位到Handler之后,DispatcherServlet会将得到的Handler告知HandlerAdapter,HandlerAdapter再根据请求去定位请求的具体处理方法是哪一个。

职责

在HandlerMapping返回处理请求的Controller实例后,需要一个帮助定位具体请求方法的处理类,这个类就是HandlerAdapter,HandlerAdapter是处理器适配器,Spring MVC通过HandlerAdapter来实际调用处理函数。例如Spring MVC自动注册的AnnotationMethodHandlerAdpater,HandlerAdapter定义了如何处理请求的策略,通过请求url、请求Method和处理器的requestMapping定义,最终确定使用处理类的哪个方法来处理请求,并检查处理类相应处理方法的参数以及相关的Annotation配置,确定如何转换需要的参数传入调用方法,并最终调用返回ModelAndView。DispatcherServlet中根据HandlerMapping找到对应的handler
method后,首先检查当前工程中注册的所有可用的handlerAdapter,根据handlerAdapter中的supports方法找到可以使用的handlerAdapter。通过调用handlerAdapter中的handler方法来处理及准备handler method的参数及annotation(这就是spring mvc如何将request中的参数变成handle method中的输入参数的地方),最终调用实际的handler method。

handlerAdapter接口

public abstract interface HandlerAdapter
{
  public abstract boolean supports(Object paramObject);

  public abstract ModelAndView handle(HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse, Object paramObject)
    throws Exception;

  public abstract long getLastModified(HttpServletRequest paramHttpServletRequest, Object paramObject);
}

该接口定义了三个方法,support方法的作用是判断处理适配器是不是支持该Handler。hanle方法,调用对应的Handler中适配到的方法,并返回一个ModelView。第三个方法不确定干嘛用的。

AnnotationMethodHandlerAdpater

supports方法实现

其中又调用了getMethodResolver这个方法后面又涉及到了很多东西,我看的不是很懂就不往更深的说了。它的主要逻辑是根据传入handler去取得ServletHandlerMethodResolver,这个ServletHandlerMethodResolver的作用可以简单的认为为解析能作为serlvet使用的方法。

public boolean supports(Object handler) {
        return getMethodResolver(handler).hasHandlerMethods();
    }
private ServletHandlerMethodResolver getMethodResolver(Object handler) {
    Class handlerClass = ClassUtils.getUserClass(handler);
    ServletHandlerMethodResolver resolver = this.methodResolverCache.get(handlerClass);
    if (resolver == null) {
        resolver = new ServletHandlerMethodResolver(handlerClass);
        this.methodResolverCache.put(handlerClass, resolver);
    }
    return resolver;
}  

handl方法实现

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {  

        if (AnnotationUtils.findAnnotation(handler.getClass(), SessionAttributes.class) != null) {
            // Always prevent caching in case of session attribute management.
            checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
            // Prepare cached set of session attributes names.
        }
        else {
            // Uses configured default cacheSeconds setting.
            checkAndPrepare(request, response, true);
        }  

        // Execute invokeHandlerMethod in synchronized block if required.
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized (mutex) {
                    return invokeHandlerMethod(request, response, handler);
                }
            }
        }  

        return invokeHandlerMethod(request, response, handler);
    } 

这个方法中的重点在于invokeHandlerMethod

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {  

        ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
        Method handlerMethod = methodResolver.resolveHandlerMethod(request);
        ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        ExtendedModelMap implicitModel = new BindingAwareModelMap();  

        Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
        ModelAndView mav =
                methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
        methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
        return mav;
    }  

其实它干的事情就是取得了handler中的对应请求的可执行方法,还是通过getMethodResolver方法实现的。在supports方法中已经构建了,所以这里调用的时候直接去缓存中取得就好了。

小结:handlerAdapter这个类的作用就是接过handlermapping解析请求得到的handler对象。在更精确的定位到能够执行请求的方法。

时间: 2024-10-13 21:21:11

Spring学习总结(2.3)-Spring MVC:handlerAdapter的相关文章

《Spring学习笔记》:Spring、Hibernate、struts2的整合(以例子来慢慢讲解,篇幅较长)

<Spring学习笔记>:Spring.Hibernate.struts2的整合(以例子来慢慢讲解,篇幅较长) 最近在看马士兵老师的关于Spring方面的视频,讲解的挺好的,到了Spring.Hibernate.struts2整合这里,由于是以例子的形式来对Spring+Hibernate+struts2这3大框架进行整合,因此,自己还跟着写代码的过程中,发现还是遇到了很多问题,因此,就记录下. 特此说明:本篇博文完全参考于马士兵老师的<Spring视频教程>. 本篇博文均以如下这

Spring学习笔记一(Spring核心思想)

通过学习<Spring in action (Third edition)>的第一章,我大概了解了Spring的基本思想: 1,依赖注入(Dependnecy Injection): 在不使用Spring框架的情况下,一个类要跟另一个类建立联系,可能会使用如下的模式: class A{...} class B{ private A a; ...       } 这样的话,每次实例化一个B的对象,如b1,必定实例化一个A的对象,如a1,并且b1和a1是紧耦合的,b1牢牢地和a1绑定在一起了.他们

spring学习二:根据spring原理自己写个spring

请先看我另一篇文章:"Spring学习一:IOC(控制反转)和AOP(面向切面)的xml配置和注解方式"中大概知道他的简单用法 那我自己想写一个简单sping,注解的方式以后再写 方式:1.解析xml配置 2.使用java的反射机制生产动态代理对象 3.扫描类上的注解,再用反射(没写) 代码如下(简单实现,重原理轻代码,不喜勿喷) xml配置我就直接用我上一篇spring-test的配置了,代码也用上一篇的,但解析的时候是用自己写的,没有用调用任何spring API代码 <?x

Spring学习系列笔记之Spring心得

1 解释一下Dependency injection(DI依赖注入)和IOC(Inversion of control,控制反转)? 答:1.1:Dependency injection(DI依赖注入): 就是说将一个目标与目标对象之间的依赖通过Spring容器来实现注入,这样使得与传统的通过自己写代码来创建对象的方式完全颠倒过来了,这就是控制反转的由来吧. 我觉得用口头举例子来说明DI更方便,更清晰.通过DI机制,降低了替换业务对象的复杂性. 依赖注入主要有两种方式来实现: a:设值注入.  

spring学习(一)spring简介

Spring简介: Spring 框架是 Java 应用最广的框架,它的成功来源于理念,而不是技术本身,它的理念包括 IoC (Inversion of Control,控制反转) 和 AOP(Aspect Oriented Programming,面向切面编程). 什么是框架: 框架:是能完成一定功能的半成品. 框架能够帮助我们完成的是:项目的整体框架.一些基础功能.规定了类和对象如何创建,如何协作等,当我们开发一个项目时,框架帮助我们完成了一部分功能,我们自己再完成一部分,那这个项目就完成了

Spring学习(八)spring整合struts2

一.spring框架对struts等表现层框架的整合原理 : 使用spring的ioc容器管理struts中用于处理请求的Action 将Action配置成ioc容器中的bean 延伸:spring对持久层框架/技术的整合原理 (封装) : 提供模板类封装对应技术/框架的开发流程 通过对模板类的使用,实现对传统开发流程的"代替". 二.整合方式: 插件方式 struts2为了实现对spring框架整合,也提供了一个插件的配置文件struts-plugin.xml struts2-spr

Spring学习(2)Spring 常用注解

Spring 常用注解 使用注解来构造IoC容器 用注解来向Spring容器注册Bean.需要在applicationContext.xml中注册<context:component-scanbase-package="pagkage1[,pagkage2,-,pagkageN]"/>. 如:在base-package指明一个包 1 <context:component-scan base-package="cn.gacl.java"/> 表

Spring学习(九)--Spring的AOP

1.配置ProxyFactoryBean Spring IOC容器中创建Spring AOP的方法. (1)配置ProxyFactoryBean的Advisor通知器 通知器实现定义了对目标对象进行增强的切面行为,即Advice通知. (2)定义ProxyFactoryBean类 设定实现AOP的重要属性,如proxyInterface.interceptorNames.target等. interceptorNames:需要定义的通知器,通知器在proxyFactoryBean的配置下,通过代

spring学习(一)—— spring mvc

目的 了解Spring mvc 学习对象 https://github.com/spring-projects/spring-mvc-showcase 学习收获 1. 自定义注解 // 以下是注解接口Target(value={ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MaskFor