SpringMVC源码解析HandlerMethod

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: SpringMVC源码解析HandlerMethod

被 RequestMapping 注解封印的方法模型类。


封装了关于处理器方法信息的方法和bean类 。 提供了对方法参数,方法返回值,方法注释等方便地访问入口。


该类可以使用bean实例或具有bean名称(例如lazy-init bean,prototype bean)来创建。 使用createWithResolvedBean()获得HandlerMethod实例,被BeanFactory解析过的。

1 字段

  // Object类型,可以是Bean,也可以是个String 的 BeanName
  private final Object bean;
  // 如果是BeanName,就靠它拿到Bean实例
  @Nullable
  private final BeanFactory beanFactory;
  private final Class<?> beanType; // 该方法所属的类
  private final Method method; // 该方法本身
  private final Method bridgedMethod; // 被桥接的方法,如果method是原生的,它的值同method
  // 方法参数的类实例 一个MethodParameter就是一个入参
  private final MethodParameter[] parameters;
  @Nullable
  private HttpStatus responseStatus; // http状态码(负责处理和返回)
  @Nullable
  private String responseStatusReason; // 状态码原因
  // 通过createWithResolvedBean()解析此handlerMethod实例的handlerMethod。
  @Nullable
  private HandlerMethod resolvedFromHandlerMethod;
  // 接口入参上的注解
  @Nullable
  private volatile List<Annotation[][]> interfaceParameterAnnotations;

构造器

  // 它的构造方法众多  此处我只写出关键的步骤
  public HandlerMethod(Object bean, Method method) {
    ...
    this.beanType = ClassUtils.getUserClass(bean);
    this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
    this.parameters = initMethodParameters();
    ...
    evaluateResponseStatus();
  }
  // 这个构造方法抛出了一个异常NoSuchMethodException 
  public HandlerMethod(Object bean, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
    ...
    this.method = bean.getClass().getMethod(methodName, parameterTypes);
    this.parameters = initMethodParameters();
    ...
    evaluateResponseStatus();
  }
  // 此处传的是BeanName
  public HandlerMethod(String beanName, BeanFactory beanFactory, Method method) {
    ...
    // 这部判断:这个BeanName是必须存在的
    Class<?> beanType = beanFactory.getType(beanName);
    if (beanType == null) {
      throw new IllegalStateException("Cannot resolve bean type for bean with name '" + beanName + "'");
    }
    this.parameters = initMethodParameters();
    ...
    evaluateResponseStatus();
  }
  // 供给子类copy使用的
  protected HandlerMethod(HandlerMethod handlerMethod) { ... }
  // 所有构造都执行了两个方法:initMethodParameters和evaluateResponseStatus

API

createWithResolvedBean

如果所提供的实例包含一个bean的名称,而不是一个对象实例。

则从 bean 工厂解析该名称得到 bean 类(@Component 注解的类),再创建HandlerMethod并返回

image.png

  // 初始化该方法所有的入参,此处使用的是内部类HandlerMethodParameter
  // 注意:处理了泛型的~~~
  private MethodParameter[] initMethodParameters() {
    int count = this.bridgedMethod.getParameterCount();
    MethodParameter[] result = new MethodParameter[count];
    for (int i = 0; i < count; i++) {
      HandlerMethodParameter parameter = new HandlerMethodParameter(i);
      GenericTypeResolver.resolveParameterType(parameter, this.beanType);
      result[i] = parameter;
    }
    return result;
  }
  // 看看方法上是否有标注了@ResponseStatus注解(接口上或者父类 组合注解上都行)
  // 若方法上没有,还会去所在的类上去看看有没有标注此注解
  // 主要只解析这个注解,把它的两个属性code和reason拿过来,最后就是返回它俩了~~~
  // code状态码默认是HttpStatus.INTERNAL_SERVER_ERROR-->(500, "Internal Server Error")
  private void evaluateResponseStatus() {
    ResponseStatus annotation = getMethodAnnotation(ResponseStatus.class);
    if (annotation == null) {
      annotation = AnnotatedElementUtils.findMergedAnnotation(getBeanType(), ResponseStatus.class);
    }
    if (annotation != null) {
      this.responseStatus = annotation.code();
      this.responseStatusReason = annotation.reason();
    }
  }
  ... // 省略所有属性的get方法(无set方法)
  // 返回方法返回值的类型  此处也使用的MethodParameter 
  public MethodParameter getReturnType() {
    return new HandlerMethodParameter(-1);
  }
  // 注意和上面的区别。举个列子:比如方法返回的是Object,但实际return “fsx”字符串
  // 那么上面返回永远是Object.class,下面你实际的值是什么类型就是什么类型
  public MethodParameter getReturnValueType(@Nullable Object returnValue) {
    return new ReturnValueMethodParameter(returnValue);
  }
  // 该方法的返回值是否是void
  public boolean isVoid() {
    return Void.TYPE.equals(getReturnType().getParameterType());
  }
  // 返回标注在方法上的指定类型的注解   父方法也成
  // 子类ServletInvocableHandlerMethod对下面两个方法都有复写~~~
  @Nullable
  public <A extends Annotation> A getMethodAnnotation(Class<A> annotationType) {
    return AnnotatedElementUtils.findMergedAnnotation(this.method, annotationType);
  }
  public <A extends Annotation> boolean hasMethodAnnotation(Class<A> annotationType) {
    return AnnotatedElementUtils.hasAnnotation(this.method, annotationType);
  }
  // resolvedFromHandlerMethod虽然它只能被构造进来,但是它实际是铜鼓调用下面方法赋值
  @Nullable
  public HandlerMethod getResolvedFromHandlerMethod() {
    return this.resolvedFromHandlerMethod;
  }
  public String getShortLogMessage() {
    return getBeanType().getName() + "#" + this.method.getName() + "[" + this.method.getParameterCount() + " args]";
  }
  // 这个方法是提供给内部类HandlerMethodParameter来使用的~~ 它使用的数据结构还是蛮复杂的
  private List<Annotation[][]> getInterfaceParameterAnnotations() {
    List<Annotation[][]> parameterAnnotations = this.interfaceParameterAnnotations;
    if (parameterAnnotations == null) {
      parameterAnnotations = new ArrayList<>();
      // 遍历该方法所在的类所有的实现的接口们(可以实现N个接口嘛)
      for (Class<?> ifc : this.method.getDeclaringClass().getInterfaces()) {
        // getMethods:拿到所有的public的方法,包括父接口的  接口里的私有方法可不会获取来
        for (Method candidate : ifc.getMethods()) {
          // 判断这个接口方法是否正好是当前method复写的这个~~~
          // 刚好是复写的方法,那就添加进来,标记为接口上的注解们~~~
          if (isOverrideFor(candidate)) {
            // getParameterAnnotations返回的是个二维数组~~~~
            // 因为参数有多个,且每个参数前可以有多个注解
            parameterAnnotations.add(candidate.getParameterAnnotations());
          }
        }
      }
      this.interfaceParameterAnnotations = parameterAnnotations;
    }
    return parameterAnnotations;
  }
  // 看看内部类的关键步骤
  protected class HandlerMethodParameter extends SynthesizingMethodParameter {
    @Nullable
    private volatile Annotation[] combinedAnnotations;
    ...
    // 父类只会在本方法拿,这里支持到了接口级别
    @Override
    public Annotation[] getParameterAnnotations() {
      Annotation[] anns = this.combinedAnnotations;
      if (anns == null) { // 都只需要解析一次
        anns = super.getParameterAnnotations();
        int index = getParameterIndex();
        if (index >= 0) { // 有入参分析
          for (Annotation[][] ifcAnns : getInterfaceParameterAnnotations()) {
            if (index < ifcAnns.length) {
              Annotation[] paramAnns = ifcAnns[index];
              if (paramAnns.length > 0) {
                List<Annotation> merged = new ArrayList<>(anns.length + paramAnns.length);
                merged.addAll(Arrays.asList(anns));
                for (Annotation paramAnn : paramAnns) {
                  boolean existingType = false;
                  for (Annotation ann : anns) {
                    if (ann.annotationType() == paramAnn.annotationType()) {
                      existingType = true;
                      break;
                    }
                  }
                  if (!existingType) {
                    merged.add(adaptAnnotation(paramAnn));
                  }
                }
                anns = merged.toArray(new Annotation[0]);
              }
            }
          }
        }
        this.combinedAnnotations = anns;
      }
      return anns;
    }
  }
  // 返回值的真正类型
  private class ReturnValueMethodParameter extends HandlerMethodParameter {
    @Nullable
    private final Object returnValue;
    public ReturnValueMethodParameter(@Nullable Object returnValue) {
      super(-1); // 此处传的-1哦~~~~ 比0小是很有意义的
      this.returnValue = returnValue;
    }
    ...
    // 返回值类型使用returnValue
    @Override
    public Class<?> getParameterType() {
      return (this.returnValue != null ? this.returnValue.getClass() : super.getParameterType());
    }
  }
}

继承树

image.png

子类都有invoke能力

目录
相关文章
|
6天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
6天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
6天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
6天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
25天前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
7天前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。
|
7月前
|
设计模式 前端开发 JavaScript
Spring MVC(一)【什么是Spring MVC】
Spring MVC(一)【什么是Spring MVC】
|
6月前
|
设计模式 前端开发 Java
【Spring MVC】快速学习使用Spring MVC的注解及三层架构
【Spring MVC】快速学习使用Spring MVC的注解及三层架构
110 1
|
6月前
|
前端开发 Java 应用服务中间件
Spring框架第六章(SpringMVC概括及基于JDK21与Tomcat10创建SpringMVC程序)
Spring框架第六章(SpringMVC概括及基于JDK21与Tomcat10创建SpringMVC程序)
|
7月前
|
前端开发 Java 关系型数据库
基于ssm框架旅游网旅游社交平台前后台管理系统(spring+springmvc+mybatis+maven+tomcat+html)
基于ssm框架旅游网旅游社交平台前后台管理系统(spring+springmvc+mybatis+maven+tomcat+html)

推荐镜像

更多