【小家Spring】Spring标准处理组件大合集(ParameterNameDiscoverer、AutowireCandidateResolver、ResolvableType。。。)(上)

简介: 【小家Spring】Spring标准处理组件大合集(ParameterNameDiscoverer、AutowireCandidateResolver、ResolvableType。。。)(上)

前言


本篇博文更像是一个工具文章,在阅读Spring源码的时候,经常会遇见一些处理器、提供器之类的组件,有的时候不深入去理解它的含义,确实还读不下去了。


为了方便自己流畅的阅读下去,特开本文记录一些关键的,使用的Spring提供的处理组件,尽量的解释清楚它们的作用甚至原理,以便我们能更自由的阅读,甚至运为己用~

ParameterNameDiscoverer:获取方法参数名称的工具


DefaultParameterNameDiscoverer:它其实就是个聚合的作用:

// Spring4.0后出现的类(伴随着StandardReflectionParameterNameDiscoverer一起出现的)
public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer {
  private static final boolean kotlinPresent =
      ClassUtils.isPresent("kotlin.Unit", DefaultParameterNameDiscoverer.class.getClassLoader());
  public DefaultParameterNameDiscoverer() {
    // 这里非常非常需要注意的一点是:用于存储的是一个LinkedList(见父类:PrioritizedParameterNameDiscoverer)
    // LinkedList是先进先出的。所以for循环遍历的时候,会最先执行Kotlin、Standard、Local... 按照这个优先级
    if (kotlinPresent) {
      addDiscoverer(new KotlinReflectionParameterNameDiscoverer());
    }
    addDiscoverer(new StandardReflectionParameterNameDiscoverer());
    addDiscoverer(new LocalVariableTableParameterNameDiscoverer());
  }
}


这里面就是给注册进去了实际意义上干事情的三个ParameterNameDiscoverer。然后它自己的方法getParameterNames和getParameterNames都由注册进来的们去完成~~~~~~~方法都在它的父类:

PrioritizedParameterNameDiscoverer


// Spring2.0就出现了。它的一个原则很简单:这么多发现器,按照顺序执行,随获取到了就算谁的
public class PrioritizedParameterNameDiscoverer implements ParameterNameDiscoverer {
  private final List<ParameterNameDiscoverer> parameterNameDiscoverers = new LinkedList<>();
  public void addDiscoverer(ParameterNameDiscoverer pnd) {
    this.parameterNameDiscoverers.add(pnd);
  }
  @Override
  @Nullable
  public String[] getParameterNames(Method method) {
    for (ParameterNameDiscoverer pnd : this.parameterNameDiscoverers) {
      String[] result = pnd.getParameterNames(method);
      if (result != null) {
        return result;
      }
    }
    return null;
  }
  @Override
  @Nullable
  public String[] getParameterNames(Constructor<?> ctor) {
    for (ParameterNameDiscoverer pnd : this.parameterNameDiscoverers) {
      String[] result = pnd.getParameterNames(ctor);
      if (result != null) {
        return result;
      }
    }
    return null;
  }
}

那么接下来说说:StandardReflectionParameterNameDiscoverer和LocalVariableTableParameterNameDiscoverer


StandardReflectionParameterNameDiscoverer:


Spring4.0提供 ,但是也得jdk8及以上版本使用。


Java.lang.reflect 包中提供了很多方法,获取所有的方法,获取所有的参数类型等,但是却没有一个方法能够帮助我们获取方法的参数名列表。JDK提供了方法弥补了这个缺陷

public class StandardReflectionParameterNameDiscoverer implements ParameterNameDiscoverer {
  @Override
  @Nullable
  public String[] getParameterNames(Method method) {
    return getParameterNames(method.getParameters());
  }
  @Override
  @Nullable
  public String[] getParameterNames(Constructor<?> ctor) {
    return getParameterNames(ctor.getParameters());
  }
  // 因为Parameter这个类是JDK8以上才提供的
  @Nullable
  private String[] getParameterNames(Parameter[] parameters) {
    String[] parameterNames = new String[parameters.length];
    for (int i = 0; i < parameters.length; i++) {
      Parameter param = parameters[i];
      if (!param.isNamePresent()) {
        return null;
      }
      parameterNames[i] = param.getName();
    }
    return parameterNames;
  }
}


LocalVariableTableParameterNameDiscoverer:


Spring2.0就有了,对JDK版本没啥要求,完全Spring自己实现的获取字段名称,逻辑复杂些,效率稍微低一点。


原理是:通过ASM提供的通过字节码获取方法的参数名称,Spring给我们集成了这个提供了这个类,我们只需要简单的使用即可。


备注:这个处理在我们Controller方法入参自动映射时,我们发现我们并不需要写@RequestParam("aaa")这样的注解,也能给自动映射上值,其实底层就运用了它去把这个key分析出来,然后去request里面拿的~

下面看一个Demo吧:

public class Main {
    private static final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
    public void testArguments(String test, Integer myInteger, boolean booleanTest) {
    }
    public void test() {
    }
    public static void main(String[] args) {
        Method[] methods = Main.class.getDeclaredMethods();
        for (Method method : methods) {
            String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
            System.out.println("方法:" + method.getName() + " 参数为:" + Arrays.asList(parameterNames));
        }
    }
}


输出为:


方法:main 参数为:[args]
方法:test 参数为:[]
方法:testArguments 参数为:[test, myInteger, booleanTest]


接下来,我们什么都不改,只改一句话:

private static final ParameterNameDiscoverer parameterNameDiscoverer = new StandardReflectionParameterNameDiscoverer();


运行看看效果:也能除数一样的效果

方法:main 参数为:[args]
方法:test 参数为:[]
方法:testArguments 参数为:[test, myInteger, booleanTest]


这里面需要特别注意了,StandardReflectionParameterNameDiscoverer的使用条件有两个

1、比如是JDK8以上版本

2、必须编译的时候有带上参数:javac -parameters


那么有小伙伴就疑问了,为何我上面编译没加参数也好使呢?这里面小伙伴务必注意了:如果你使用的idea的IDE,它里面默认编辑就带有此参数的:(Compiler-Java Compiler)

image.png

若你把它去掉,你的结果会如下:(建议各位小伙伴都试试)


// 去掉这个参数后,获取到的parameterNames 就是null了
// 再次提示一下:若还没效果,请手动重新编译对应文件
String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);


好了,讲解完这个,讲视线继续移步到上面的自动注入吧。

为了获取最好的兼容性,推荐使用DefaultParameterNameDiscoverer,而不是直接使用某个具体的Discoverer


相关文章
|
6月前
|
NoSQL 安全 Java
深入理解 RedisConnectionFactory:Spring Data Redis 的核心组件
在 Spring Data Redis 中,`RedisConnectionFactory` 是核心组件,负责创建和管理与 Redis 的连接。它支持单机、集群及哨兵等多种模式,为上层组件(如 `RedisTemplate`)提供连接抽象。Spring 提供了 Lettuce 和 Jedis 两种主要实现,其中 Lettuce 因其线程安全和高性能特性被广泛推荐。通过手动配置或 Spring Boot 自动化配置,开发者可轻松集成 Redis,提升应用性能与扩展性。本文深入解析其作用、实现方式及常见问题解决方法,助你高效使用 Redis。
593 4
|
7月前
|
安全 Java 数据安全/隐私保护
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
259 0
|
7月前
|
负载均衡 Java Nacos
Spring Cloud五大组件
Spring Cloud五大组件
|
3月前
|
JSON 前端开发 Java
Spring MVC 核心组件与请求处理机制详解
本文解析了 Spring MVC 的核心组件及请求流程,核心组件包括 DispatcherServlet(中央调度)、HandlerMapping(URL 匹配处理器)、HandlerAdapter(执行处理器)、Handler(业务方法)、ViewResolver(视图解析),其中仅 Handler 需开发者实现。 详细描述了请求执行的 7 步流程:请求到达 DispatcherServlet 后,经映射器、适配器找到并执行处理器,再通过视图解析器渲染视图(前后端分离下视图解析可省略)。 介绍了拦截器的使用(实现 HandlerInterceptor 接口 + 配置类)及与过滤器的区别
230 0
|
11月前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
906 61
|
XML 缓存 Java
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
169 10
|
XML 存储 Java
spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)
spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)
|
人工智能 自然语言处理 Java
Spring AI,Spring团队开发的新组件,Java工程师快来一起体验吧
文章介绍了Spring AI,这是Spring团队开发的新组件,旨在为Java开发者提供易于集成的人工智能API,包括机器学习、自然语言处理和图像识别等功能,并通过实际代码示例展示了如何快速集成和使用这些AI技术。
Spring AI,Spring团队开发的新组件,Java工程师快来一起体验吧
|
Java Spring
Spring的AOP组件详解
该文章主要介绍了Spring AOP(面向切面编程)组件的实现原理,包括Spring AOP的基础概念、动态代理模式、AOP组件的实现以及Spring选择JDK动态代理或CGLIB动态代理的依据。
Spring的AOP组件详解
|
Java 开发工具 Spring
【Azure 事件中心】azure-spring-cloud-stream-binder-eventhubs客户端组件问题, 实践消息非顺序可达
【Azure 事件中心】azure-spring-cloud-stream-binder-eventhubs客户端组件问题, 实践消息非顺序可达