惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Hacker News: Ask HN
Hacker News: Ask HN
N
News and Events Feed by Topic
Forbes - Security
Forbes - Security
The Last Watchdog
The Last Watchdog
TaoSecurity Blog
TaoSecurity Blog
Schneier on Security
Schneier on Security
SecWiki News
SecWiki News
V
Vulnerabilities – Threatpost
Project Zero
Project Zero
O
OpenAI News
W
WeLiveSecurity
Security Archives - TechRepublic
Security Archives - TechRepublic
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
H
Hacker News: Front Page
Cisco Talos Blog
Cisco Talos Blog
Spread Privacy
Spread Privacy
Help Net Security
Help Net Security
P
Privacy & Cybersecurity Law Blog
K
Kaspersky official blog
S
Security @ Cisco Blogs
Latest news
Latest news
AWS News Blog
AWS News Blog
U
Unit 42
Martin Fowler
Martin Fowler
阮一峰的网络日志
阮一峰的网络日志
S
Secure Thoughts
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Know Your Adversary
Know Your Adversary
Scott Helme
Scott Helme
博客园 - 司徒正美
B
Blog RSS Feed
C
Check Point Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
Docker
Google Online Security Blog
Google Online Security Blog
Jina AI
Jina AI
aimingoo的专栏
aimingoo的专栏
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Last Week in AI
Last Week in AI
月光博客
月光博客
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
SegmentFault 最新的问题
NISL@THU
NISL@THU
T
The Blog of Author Tim Ferriss
C
Cisco Blogs
Attack and Defense Labs
Attack and Defense Labs
小众软件
小众软件

博客园 - wastonl

Jvm内存以及垃圾回收相关知识 RocketMQ如何保证消息可靠性 RocketMQ整体架构 mybatis-plus易忘点笔记 SpringMVC使用Resource实现二进制传输(下载) Spring事件异步执行设计与实现 Spring Bean销毁机制 Spring Lifecycle组件 Zipkin Brave使用 Spring Boot日志系统简要介绍 spring cloud sleuth基本使用 Spring懒加载与@Lazy注解 tomcat自动刷新响应输出流缓冲区 https碎碎念 ES脚本使用 SpringMVC静态资源处理 Maven插件运行方式 如何使用Maven将项目中的依赖打进jar包 时区以及时区对于Java时间类格式化的影响 SpringMVC处理请求头、响应头、编码行为 tomcat连接处理机制和线程模型 树组件实现 JWT示例与原理 方法句柄API使用
Spring ResolvableType说明
wastonl · 2026-06-12 · via 博客园 - wastonl

背景

ResolvableType 是 Spring 框架提供的一个封装类,专门用来在运行时解析和处理复杂的泛型类型信息,解决了 Java 反射 API 在泛型处理上的不便。它可以看作是对 java.lang.reflect.Type 系列接口的更高层抽象,尤其是在处理嵌套泛型、通配符、类型变量时优势明显。

java 泛型在编译后会被擦除,常规反射只能拿到原始类型,比如 List<String> 在运行时只是 List。虽然可以通过 ParameterizedType 等接口获取一些泛型信息,但操作繁琐,且缺乏递归解析、类型变量替换等能力。

ResolvableType 能轻松做到:

  • 获取字段、方法参数、返回值上的完整泛型结构
  • 在继承层次中解析某个泛型接口的实际类型参数
  • 处理多层嵌套泛型如 Map<String, List<Integer>>

在Spring的事件机制中被广泛使用。

Java原生使用

对于以下泛型类型,没有子类的帮助下,是无法获取具体的运行时类型的

public class ApplicationListener<T> {

    void onApplicationListener(T event) {}

    public static void main(String[] args) {
        // 没有办法拿到listener对象实际的运行时泛型类型
        ApplicationListener<String> listener = new ApplicationListener<>();
    }
}

如果在有子类的情况下,便可以借助Class.getGenericSuperclass或者getGenericInterfaces方法来获取到实际的泛型类型了。

public abstract class ApplicationListener<T> {

    abstract void onApplicationListener(T event);

    static class StringApplicationListener extends ApplicationListener<String> {

        @Override
        void onApplicationListener(String event) {

        }
    }

    public static void main(String[] args) {
        ApplicationListener<String> listener = new StringApplicationListener();
        Type superclass = listener.getClass().getGenericSuperclass();
        if (superclass instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType)superclass;
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            // true
            System.out.println(actualTypeArguments[0] instanceof Class<?>);
            // class java.lang.String
            System.out.println(actualTypeArguments[0]);
        }
    }
}

ResolvableType API使用

创建 ResolvableType 实例

表格中只例举了常用几个

方法 说明
forClass(Class<?>) 包装一个原始类
forType(Type) 包装任意 java.lang.reflect.Type
forInstance(Object) 根据实例创建
forClass(Class baseType, Class implementationClass) 基于实现类推导泛型
ResolvableType forClassWithGenerics(Class, Class... ) 包含泛型

使用示例

package com.wangtao.springboottest;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.core.ResolvableType;

public class ResolvableTypeTest {

    public static class PayloadEvent<T> {

    }

    public static class StringPayloadEvent extends PayloadEvent<String> {

    }

    @Test
    public void testCreateApi() {
        ResolvableType type = ResolvableType.forClass(PayloadEvent.class);
        Assertions.assertEquals("com.wangtao.springboottest.ResolvableTypeTest$PayloadEvent<?>", type.toString());
        // 指定泛型
        type = ResolvableType.forClassWithGenerics(PayloadEvent.class, String.class);
        Assertions.assertEquals("com.wangtao.springboottest.ResolvableTypeTest$PayloadEvent<java.lang.String>", type.toString());

        // 基于实现类构建泛型
        type = ResolvableType.forClass(PayloadEvent.class, StringPayloadEvent.class);
        Assertions.assertEquals("com.wangtao.springboottest.ResolvableTypeTest$PayloadEvent<java.lang.String>", type.toString());
        // 上面底层就是这个
        type = ResolvableType.forClass(StringPayloadEvent.class).as(PayloadEvent.class);
        Assertions.assertEquals("com.wangtao.springboottest.ResolvableTypeTest$PayloadEvent<java.lang.String>", type.toString());

        StringPayloadEvent event = new StringPayloadEvent();
        // 类似forClass
        type = ResolvableType.forInstance(event);
        Assertions.assertEquals("com.wangtao.springboottest.ResolvableTypeTest$StringPayloadEvent", type.toString());
    }
}


核心方法与解析能力

方法 说明
Class<?> resolve() 返回擦除后的原生类型
ResolvableType getGeneric(int... indexes) 递归获取指定位置的泛型参数
ResolvableType[] getGenerics() 获取泛型参数数组
ResolvableType getSuperType() 父类对应的 ResolvableType,已包含子类绑定的实参
ResolvableType[] getInterfaces() 接口数组(同样绑定好实参)
ResolvableType as(Class<?> type) 将当前类型向上转型到指定父类或接口,保留泛型绑定
boolean isAssignableFrom(ResolvableType other) 类型兼容性判断,支持泛型(扩展Class.isAssignableFrom)
boolean isInstance(Object obj) 判断对象是不是当前类型的实例,支持泛型(扩展Class.isInstance)

使用示例

package com.wangtao.springboottest;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.core.ResolvableType;

import java.util.Arrays;
import java.util.List;

public class ResolvableTypeTest {

    public static class PayloadEvent<T> {

    }

    public static class StringPayloadEvent extends PayloadEvent<String> {

    }

    @Test
    public void testGetApi() {
        // 指定泛型
        ResolvableType type = ResolvableType.forClassWithGenerics(PayloadEvent.class, String.class);
        // 获取原始类型
        Assertions.assertEquals(PayloadEvent.class, type.resolve());
        // 获取第一个位置的泛型参数
        Assertions.assertEquals("java.lang.String", type.getGeneric(0).toString());
        // 构造一个嵌套的泛型结构(List<PayloadEvent<String>>)
        type = ResolvableType.forClassWithGenerics(List.class, type);
        Assertions.assertEquals("java.util.List<com.wangtao.springboottest.ResolvableTypeTest$PayloadEvent<java.lang.String>>", type.toString());
        // 递归获取,先获取第一个位置的泛型参数, 从这个结果泛型参数中继续获取第一个位置的泛型参数
        Assertions.assertEquals("java.lang.String", type.getGeneric(0, 0).toString());
        type = ResolvableType.forClassWithGenerics(PayloadEvent.class, String.class);
        // 获取泛型参数列表
        ResolvableType[] genericArr = type.getGenerics();
        Assertions.assertEquals("[java.lang.String]", Arrays.toString(genericArr));

        type = ResolvableType.forClass(StringPayloadEvent.class);
        // 获取父类型(会保留具体的泛型参数)
        Assertions.assertEquals("com.wangtao.springboottest.ResolvableTypeTest$PayloadEvent<java.lang.String>", type.getSuperType().toString());

        // 向上转型到父类型(会保留具体的泛型参数)
        type = type.as(PayloadEvent.class);
        Assertions.assertEquals("com.wangtao.springboottest.ResolvableTypeTest$PayloadEvent<java.lang.String>", type.toString());
    }
}