Spring 泛型处理 - ResolvableType、GenericTypeResolver 与通用 CRUD 基类实战
1. Java 泛型擦除机制简介
1.1 泛型擦除的本质
Java 泛型是 JDK 5 引入的特性,但在字节码层面,泛型信息仅在编译期用于类型检查,编译后的字节码中泛型参数会被擦除(Type Erasure)。这意味着以下代码无法通过反射获取运行时类型参数:
// 编译时泛型信息被擦除
List<String> list = new ArrayList<>();
// 运行时无法区分 List<String> 和 List<Integer>擦除的具体规则:
- 若泛型类型未指定边界(如
<T>),则擦除为Object - 若指定了上边界(如
<T extends Number>),则擦除为该上边界
1.2 为什么 Spring 需要处理泛型
由于泛型擦除的存在,框架在运行时无法直接获取泛型参数的具体类型。然而 Spring 大量依赖泛型来实现声明式编程,典型场景包括:
- Repository 泛型:
JpaRepository<User, Long>需要知道实体类型以构造查询 - 事件监听泛型:
GenericApplicationListener需要根据事件泛型类型匹配监听器 - 泛型转换:
GenericConverter需要根据源/目标类型的泛型参数进行类型转换 - 通用 CRUD 基类:
BaseController<T>、BaseService<T>需要在运行时获取实际类型以执行持久化操作
为解决这些问题,Spring 提供了 ResolvableType、GenericTypeResolver、ParameterizedTypeReference 等工具来在运行时解析泛型信息。
2. ResolvableType 类详解
ResolvableType 是 Spring 4.0 引入的核心泛型工具类,位于 org.springframework.core 包下。它封装了 Java 的 java.lang.reflect.Type 体系,提供了更直观易用的 API 来解析、遍历和操作泛型类型信息。
2.1 核心构造方式
public class ResolvableType implements Serializable {
// 通过 Class 构造
public static ResolvableType forClass(Class<?> clazz);
// 通过 Type 构造(支持 ParameterizedType、TypeVariable 等)
public static ResolvableType forType(Type type);
// 通过实例构造(利用 getClass() 获取运行时类型信息)
public static ResolvableType forInstance(Object instance);
// 通过 Field 构造
public static ResolvableType forField(Field field);
// 通过 MethodParameter 构造
public static ResolvableType forMethodParameter(MethodParameter methodParameter);
// 通过构造函数参数构造
public static ResolvableType forConstructorParameter(Constructor<?> constructor, int parameterIndex);
}2.2 核心方法详解
2.2.1 getGeneric() —— 获取泛型参数
getGeneric(int... indexes) 用于获取指定索引位置的泛型参数类型:
// 示例:解析 Map<String, List<Integer>>
public class MyMap extends HashMap<String, List<Integer>> {
}
ResolvableType type = ResolvableType.forClass(MyMap.class);
// 获取父类类型
ResolvableType superType = type.getSuperType(); // HashMap<String, List<Integer>>
// 获取第一个泛型参数:String
ResolvableType keyType = superType.getGeneric(0);
System.out.println(keyType.resolve()); // class java.lang.String
// 获取第二个泛型参数:List<Integer>
ResolvableType valueType = superType.getGeneric(1);
System.out.println(valueType.resolve()); // interface java.util.List
// 获取 List<Integer> 的泛型参数:Integer
ResolvableType listGeneric = valueType.getGeneric(0);
System.out.println(listGeneric.resolve()); // class java.lang.Integer
// 链式调用
ResolvableType chainResult = superType.getGeneric(1, 0);
System.out.println(chainResult.resolve()); // class java.lang.Integer2.2.2 resolve() —— 解析为 Class
将 ResolvableType 解析为最终的 Class<?>。如果无法解析(如尚未确定类型变量),则返回 null。
public abstract class AbstractService<T, ID> {
public Class<?> resolveEntityClass() {
// 获取当前类的第一个泛型参数的实际类型
return ResolvableType.forClass(getClass())
.getSuperType() // 可能有多层继承
.getGeneric(0)
.resolve();
}
}resolve(boolean fallbackToVariable) —— 若无法解析,是否回退到 TypeVariable:
ResolvableType resolvableType = ...;
// fallbackToVariable=true 时,即使无法解析也不会返回 null,而是返回 TypeVariable 对应的 Class
Class<?> clazz = resolvableType.resolve(true);2.2.3 getSuperTypeForTypeArgument() —— 获取指定超类上的类型参数
该方法用于在继承链中定位某个接口/父类的类型参数:
// 示例
public interface BaseRepository<T, ID> {}
public interface UserRepository extends BaseRepository<User, Long> {}
ResolvableType resolvableType = ResolvableType.forClass(UserRepository.class);
// 获取 UserRepository 在 BaseRepository 上的泛型参数类型
ResolvableType[] typeArgs = resolvableType.getSuperTypeForTypeArgument(BaseRepository.class);
// typeArgs[0] = User, typeArgs[1] = Long2.2.4 asMap() / asList() —— 类型视图转换
这些方法将当前类型视为某种特定容器类型来提取泛型参数:
// asMap() —— 将类型视作 Map 并获取 Key 和 Value 的类型
public class MyMap extends HashMap<String, List<Integer>> {}
ResolvableType resolvableType = ResolvableType.forClass(MyMap.class);
ResolvableType mapType = resolvableType.asMap();
// 等价于获取 Map 上泛型参数的第二个(Value)类型
ResolvableType keyType = mapType.getGeneric(0);
ResolvableType valueType = mapType.getGeneric(1);
System.out.println(keyType.resolve()); // class java.lang.String
System.out.println(valueType.resolve()); // interface java.util.List
// asList() —— 将类型视作 List 并获取元素类型
public class MyList extends ArrayList<String> {}
ResolvableType listType = ResolvableType.forClass(MyList.class).asList();
ResolvableType elementType = listType.getGeneric(0);
System.out.println(elementType.resolve()); // class java.lang.String2.2.5 其他重要方法
| 方法 | 说明 |
|---|---|
isArray() | 判断是否为数组类型 |
isAssignableFrom(ResolvableType) | 判断类型兼容性 |
hasUnresolvableGenerics() | 是否存在无法解析的泛型参数 |
getSource() | 获取底层的 Type 对象 |
getType() | 获取 Type 或 Class |
getNested(int nestingLevel) | 获取嵌套类型,如 Map<String, List<Integer>> 的嵌套层级 |
getInterfaces() | 获取当前类型实现的所有接口的 ResolvableType[] |
2.3 综合示例
import org.springframework.core.ResolvableType;
public class ResolvableTypeDemo {
// 定义一个多层嵌套泛型的类
static class GenericClass<K, V> {
// 字段类型为 Map<K, List<V>>
private java.util.Map<K, java.util.List<V>> map;
public java.util.Map<K, java.util.List<V>> getMap() {
return map;
}
}
// 具体化泛型
static class ConcreteClass extends GenericClass<String, Integer> {
}
public static void main(String[] args) throws Exception {
ResolvableType resolvableType = ResolvableType.forClass(ConcreteClass.class);
ResolvableType superType = resolvableType.getSuperType();
// K -> String
System.out.println("K = " + superType.getGeneric(0).resolve());
// V -> Integer
System.out.println("V = " + superType.getGeneric(1).resolve());
// 解析字段类型
ResolvableType fieldType = ResolvableType.forField(
GenericClass.class.getDeclaredField("map"));
System.out.println("Map<K, List<V>> = " + fieldType.getType());
// 字段泛型:K -> String
System.out.println("Map key resolve = " + fieldType.getGeneric(0).resolve());
// 字段泛型:List<V> -> List<Integer>
ResolvableType listValueType = fieldType.getGeneric(1);
System.out.println("Map value type = " + listValueType.resolve());
System.out.println("List<V> generic = " + listValueType.getGeneric(0).resolve());
}
}运行结果:
K = class java.lang.String
V = class java.lang.Integer
Map<K, List<V>> = java.util.Map<K, java.util.List<V>>
Map key resolve = class java.lang.String
Map value type = interface java.util.List
List<V> generic = class java.lang.Integer3. Type 体系详解
Spring 的 ResolvableType 底层依赖 Java 的 java.lang.reflect.Type 接口体系。理解这个体系是深入理解 ResolvableType 的前提。
3.1 Type 接口体系结构
Type (java.lang.reflect.Type)
├── Class — 原始类型,如 String.class、Integer.class
├── ParameterizedType — 参数化类型,如 List<String>、Map<K, V>
├── TypeVariable — 类型变量,如 T、E、K、V
├── WildcardType — 通配符类型,如 ? extends Number、? super Integer
└── GenericArrayType — 泛型数组类型,如 T[]、List<String>[]3.2 各接口详解
3.2.1 Class —— 原始类
最基础的 Type 实现,表示一个普通的 Java 类或接口:
Class<?> stringClass = String.class;
// stringClass instanceof Type -> true
// stringClass instanceof Class -> true3.2.2 ParameterizedType —— 参数化类型
表示带有泛型参数的类型,如 List<String>、Map<String, Integer> 等:
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ParameterizedTypeDemo extends HashMap<String, List<Integer>> {
public static void main(String[] args) {
ParameterizedType superType = (ParameterizedType)
ParameterizedTypeDemo.class.getGenericSuperclass();
// getRawType() —— 原始类型(不带泛型参数)
System.out.println("Raw type: " + superType.getRawType());
// 输出:class java.util.HashMap
// getActualTypeArguments() —— 实际的泛型参数数组
Type[] typeArgs = superType.getActualTypeArguments();
for (int i = 0; i < typeArgs.length; i++) {
System.out.println("TypeArg[" + i + "]: " + typeArgs[i]);
}
// 输出:
// TypeArg[0]: class java.lang.String
// TypeArg[1]: java.util.List<java.lang.Integer>
// getOwnerType() —— 拥有者类型(用于内部类)
System.out.println("Owner type: " + superType.getOwnerType());
// 输出:null(HashMap 不是内部类)
}
}ParameterizedType 接口定义:
public interface ParameterizedType extends Type {
// 获取原始的 Class 类型(如 List.class、Map.class)
Type getRawType();
// 获取实际的泛型参数数组
Type[] getActualTypeArguments();
// 获取拥有者类型(内部类时指向外部类)
Type getOwnerType();
}3.2.3 TypeVariable —— 类型变量
表示泛型声明中的类型变量,如 class Container<T extends Number> 中的 T:
import java.lang.reflect.TypeVariable;
public class TypeVariableDemo<T extends Number, E extends Comparable<T>> {
public static void main(String[] args) {
TypeVariable<?>[] typeParams =
TypeVariableDemo.class.getTypeParameters();
for (TypeVariable<?> tv : typeParams) {
System.out.println("Variable name: " + tv.getName());
// getBounds() —— 获取上边界
Type[] bounds = tv.getBounds();
for (Type bound : bounds) {
System.out.println(" Bound: " + bound);
}
// getGenericDeclaration() —— 获取声明该类型变量的类
System.out.println(" Declared by: " + tv.getGenericDeclaration());
}
}
}输出:
Variable name: T
Bound: class java.lang.Number
Declared by: class TypeVariableDemo
Variable name: E
Bound: java.lang.Comparable<T>
Declared by: class TypeVariableDemo3.2.4 WildcardType —— 通配符类型
表示泛型中的通配符表达式,如 ? extends Number、? super String:
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.List;
public class WildcardTypeDemo {
// 通配符类型:? extends Number
private List<? extends Number> wildcardExtendsList;
// 通配符类型:? super Integer
private List<? super Integer> wildcardSuperList;
public static void main(String[] args) throws Exception {
WildcardType extendsWildcard = getWildcardType(
WildcardTypeDemo.class.getDeclaredField("wildcardExtendsList"));
WildcardType superWildcard = getWildcardType(
WildcardTypeDemo.class.getDeclaredField("wildcardSuperList"));
printWildcardInfo("? extends Number", extendsWildcard);
printWildcardInfo("? super Integer", superWildcard);
}
private static WildcardType getWildcardType(java.lang.reflect.Field field) {
ParameterizedType type = (ParameterizedType) field.getGenericType();
return (WildcardType) type.getActualTypeArguments()[0];
}
private static void printWildcardInfo(String name, WildcardType wc) {
System.out.println(name + ":");
System.out.println(" Upper bounds:");
for (Type bound : wc.getUpperBounds()) {
System.out.println(" " + bound);
}
System.out.println(" Lower bounds:");
for (Type bound : wc.getLowerBounds()) {
System.out.println(" " + bound);
}
}
}输出:
? extends Number:
Upper bounds:
class java.lang.Number
Lower bounds: (empty)
? super Integer:
Upper bounds:
class java.lang.Object
Lower bounds:
class java.lang.IntegerWildcardType 接口定义:
public interface WildcardType extends Type {
// 获取上边界(对于 ? extends T,返回 [T];无上边界返回 [Object])
Type[] getUpperBounds();
// 获取下边界(对于 ? super T,返回 [T];无下边界返回空数组)
Type[] getLowerBounds();
}3.2.5 GenericArrayType —— 泛型数组类型
表示泛型数组类型,如 T[]、List<String>[]:
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
public class GenericArrayTypeDemo<T> {
// 元素类型为类型变量的数组
private T[] genericArray;
// 元素类型为参数化类型的数组
private List<String>[] parameterizedArray;
public static void main(String[] args) throws Exception {
GenericArrayType genericArrayType = (GenericArrayType)
GenericArrayTypeDemo.class.getDeclaredField("genericArray").getGenericType();
System.out.println("Generic array: " + genericArrayType);
// getGenericComponentType() 返回 T
System.out.println("Component type: " + genericArrayType.getGenericComponentType());
GenericArrayType paramArrayType = (GenericArrayType)
GenericArrayTypeDemo.class.getDeclaredField("parameterizedArray").getGenericType();
System.out.println("Parameterized array: " + paramArrayType);
ParameterizedType paramType = (ParameterizedType) paramArrayType.getGenericComponentType();
System.out.println("Component raw type: " + paramType.getRawType());
System.out.println("Component arg: " + paramType.getActualTypeArguments()[0]);
}
}3.3 Spring 对 Type 体系的封装
ResolvableType 内部持有 Type 对象,并通过 TypeResolverProvider 等机制解析类型变量,以下是 Type 到 ResolvableType 的映射:
| Java Type | ResolvableType 构造方式 | resolve() 行为 |
|---|---|---|
Class | ResolvableType.forClass(clazz) | 返回该类本身 |
ParameterizedType | ResolvableType.forType(type) | 返回 rawType |
TypeVariable | 通过 forClass() 自动处理 | 尝试解析为实际类型,否则返回 null |
WildcardType | 通过 forType() 自动处理 | 返回第一个上边界 |
GenericArrayType | 通过 forType() 自动处理 | 返回数组 Class |
4. GenericTypeResolver 解析泛型参数
GenericTypeResolver 是 Spring 提供的另一个泛型解析工具类,位于 org.springframework.core 包。与 ResolvableType 不同,它更侧重于针对特定场景提供快捷解析方法。
4.1 核心方法
public abstract class GenericTypeResolver {
// 解析类在特定目标类上的泛型参数
// 例如:解析 UserRepository 在 BaseRepository 上的泛型参数
public static Class<?> resolveTypeArgument(
Class<?> clazz, Class<?> genericIfc);
// 批量解析
public static Class<?>[] resolveTypeArguments(
Class<?> clazz, Class<?> genericIfc);
// 解析 TypeVariable(需要 TypeVariableMap)
public static Type resolveType(Type genericType, Map<TypeVariable<?>, Type> map);
// 获取类型变量映射表
public static Map<TypeVariable<?>, Type> getTypeVariableMap(Class<?> clazz);
// 缓存版本,返回 ResolvableType
@Nullable
public static ResolvableType resolveType(ResolvableType type);
}4.2 使用示例
import org.springframework.core.GenericTypeResolver;
public interface BaseRepository<T, ID> {
}
public class UserRepository implements BaseRepository<User, Long> {
}
public class GenericTypeResolverDemo {
public static void main(String[] args) {
// 解析单个类型参数
Class<?> entityClass = GenericTypeResolver.resolveTypeArgument(
UserRepository.class, BaseRepository.class);
System.out.println("Entity type: " + entityClass); // class User
// 解析多个类型参数
Class<?>[] typeArgs = GenericTypeResolver.resolveTypeArguments(
UserRepository.class, BaseRepository.class);
System.out.println("Type args: " + Arrays.toString(typeArgs));
// [class User, class Long]
}
}4.3 GenericTypeResolver 实现原理
GenericTypeResolver 内部维护了一个缓存(ConcurrentReferenceHashMap),用于缓存每个类的类型变量映射表。
// 核心实现概览
public static Class<?> resolveTypeArgument(Class<?> clazz, Class<?> genericIfc) {
// 获取类型变量映射表
Map<TypeVariable<?>, Type> typeVariableMap = getTypeVariableMap(clazz);
// 查找目标接口上的类型变量
Type[] arguments = getTypeArguments(
ResolvableType.forClass(clazz).as(genericIfc).getType());
// 根据映射表解析
// ...
return (Class<?>) resolveType(arguments[0], typeVariableMap);
}
// 类型变量映射表构建
public static Map<TypeVariable<?>, Type> getTypeVariableMap(Class<?> clazz) {
// 从缓存获取
Map<TypeVariable<?>, Type> map = CACHE.get(clazz);
if (map == null) {
// 构建映射表
map = new HashMap<>();
buildTypeVariableMap(ResolvableType.forClass(clazz), map);
CACHE.put(clazz, map);
}
return map;
}4.4 与 ResolvableType 的选择
| 场景 | 推荐工具 |
|---|---|
| 解析具体类上的泛型参数 | GenericTypeResolver.resolveTypeArgument() |
| 需要链式/嵌套解析 | ResolvableType |
| 需要处理 Map、List 等容器的泛型 | ResolvableType.asMap(), asList() |
| 解析字段、方法参数上的泛型 | ResolvableType.forField(), forMethodParameter() |
| 只需要最终 Class 结果 | GenericTypeResolver |
| 需要完整的类型信息(包括嵌套泛型) | ResolvableType |
5. ParameterizedTypeReference 的实现原理
5.1 核心机制:利用匿名内部类保留泛型信息
ParameterizedTypeReference 是 Spring 提供的一个抽象类,它的核心原理是利用匿名内部类在编译时会保留泛型信息这一特性。
public abstract class ParameterizedTypeReference<T> {
private final Type type;
protected ParameterizedTypeReference() {
// 获取子类的 Class 对象
Class<?> parameterizedTypeReferenceSubclass = findParameterizedTypeReferenceSubclass(getClass());
// 获取父类 ParameterizedTypeReference<T> 的类型参数
Type type = parameterizedTypeReferenceSubclass.getGenericSuperclass();
// 强制转换为 ParameterizedType
ParameterizedType parameterizedType = (ParameterizedType) type;
// 获取实际的泛型参数
this.type = parameterizedType.getActualTypeArguments()[0];
}
public Type getType() {
return this.type;
}
// 关键辅助方法
private static Class<?> findParameterizedTypeReferenceSubclass(Class<?> child) {
Class<?> parent = child.getSuperclass();
// 向上查找继承链,找到直接继承 ParameterizedTypeReference 的子类
while (parent != Object.class) {
if (parent == ParameterizedTypeReference.class) {
return child;
}
child = parent;
parent = child.getSuperclass();
}
throw new IllegalStateException("...");
}
}5.2 使用示例
// 正确用法:使用匿名内部类
ParameterizedTypeReference<List<String>> typeRef =
new ParameterizedTypeReference<List<String>>() {};
System.out.println(typeRef.getType());
// 输出:java.util.List<java.lang.String>
// 错误用法:直接使用匿名内部类时不带泛型信息
// ❌ 这会丢失泛型信息
ParameterizedTypeReference<List<String>> wrongRef =
new ParameterizedTypeReference<List<String>>() {
// 这里没有 {} 中的任何内容,仍然可以工作
// 但需要正确创建匿名内部类
};
// 实际上泛型信息被正确保留的原因是匿名内部类的存在
// 匿名内部类的字节码会在常量池中记录父类的 Signature 属性5.3 字节码层面的原理
Java 编译器在编译匿名内部类时,会在 .class 文件的 Signature 属性中记录父类的完整泛型信息:
// 源代码
ParameterizedTypeReference<List<String>> ref =
new ParameterizedTypeReference<List<String>>() {};
// 编译后的字节码等价于(伪代码)
// class $1 extends ParameterizedTypeReference<List<String>> {}
// Signature 属性: Lorg/springframework/core/ParameterizedTypeReference<
// Ljava/util/List<Ljava/lang/String;>;>;getGenericSuperclass() 方法会读取这个 Signature 属性,返回携带泛型信息的 ParameterizedType,从而避免了泛型擦除。
5.4 典型应用场景
ParameterizedTypeReference 最常用于 RestTemplate 和 WebClient 的泛型响应类型解析:
// RestTemplate 示例
ParameterizedTypeReference<List<User>> typeRef =
new ParameterizedTypeReference<List<User>>() {};
ResponseEntity<List<User>> response = restTemplate.exchange(
"http://api.example.com/users",
HttpMethod.GET,
null,
typeRef);
List<User> users = response.getBody();
// WebClient 示例
Flux<User> users = webClient.get()
.uri("/users")
.retrieve()
.bodyToFlux(User.class);
// 或者使用 ParameterizedTypeReference
Mono<List<User>> usersMono = webClient.get()
.uri("/users")
.retrieve()
.bodyToMono(new ParameterizedTypeReference<List<User>>() {});6. 泛型在 Spring 内部的应用
6.1 Repository 泛型处理
Spring Data JPA 中,JpaRepository<T, ID> 是最典型的泛型应用。框架通过泛型解析来确定实体类型和主键类型:
// Spring Data JPA 内部实现
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
}
// SimpleJpaRepository 是 JpaRepository 的默认实现
public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID> {
private final Class<T> entityClass;
public SimpleJpaRepository(JpaEntityInformation<T, ?> entityInformation,
EntityManager entityManager) {
// entityInformation 中包含了实体类型信息
this.entityClass = entityInformation.getJavaType();
}
// 另一种方式:通过泛型解析获取实体类型
@SuppressWarnings("unchecked")
protected Class<T> getDomainClass() {
ResolvableType resolvableType = ResolvableType.forClass(getClass())
.as(SimpleJpaRepository.class);
return (Class<T>) resolvableType.getGeneric(0).resolve();
}
}Spring Data 创建 Repository 代理时,会扫描接口的泛型参数:
// 简化版代理创建逻辑
public class RepositoryFactorySupport {
public Object getRepository(Class<?> repositoryInterface) {
// 解析 Repository 接口的泛型参数
Class<?> entityClass = GenericTypeResolver.resolveTypeArgument(
repositoryInterface, Repository.class);
Class<?> idClass = GenericTypeResolver.resolveTypeArguments(
repositoryInterface, Repository.class)[1];
// 根据实体类型创建 EntityInformation
JpaEntityInformation<?, ?> entityInformation =
getEntityInformation(entityClass);
// 创建代理实例
return createProxy(repositoryInterface, entityInformation);
}
}6.2 GenericApplicationListener 事件泛型
Spring 4.2 引入的 @EventListener 注解支持泛型事件,其底层通过 ResolvableType 实现事件类型匹配:
// 泛型事件定义
public class BaseEvent<T> extends ApplicationEvent {
private final T data;
public BaseEvent(Object source, T data) {
super(source);
this.data = data;
}
public T getData() {
return data;
}
}
// 监听器定义
@Component
public class UserEventListener {
@EventListener
public void handleUserEvent(BaseEvent<User> event) {
User user = event.getData();
System.out.println("Received user: " + user.getName());
}
}Spring 内部的事件派发机制通过 GenericApplicationListener 来匹配带泛型的事件:
public class GenericApplicationListenerAdapter implements GenericApplicationListener {
private final ResolvableType declaredEventType;
public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
// 解析监听器声明的事件类型
ResolvableType listenerType = ResolvableType.forClass(delegate.getClass());
// 获取 ApplicationListener<T> 上的 T
this.declaredEventType = listenerType
.as(ApplicationListener.class)
.getGeneric(0);
}
@Override
public boolean supportsEventType(ResolvableType eventType) {
// 检查事件类型是否匹配
if (this.declaredEventType == null) {
return false;
}
// 如果声明了泛型,需要检查泛型参数是否匹配
return this.declaredEventType.isAssignableFrom(eventType);
}
}使用 @EventListener 处理泛型事件时的匹配逻辑:
// ApplicationListenerMethodAdapter 中的匹配逻辑
protected ResolvableType resolveDeclaredEventType(Method method) {
// 获取 @EventListener 方法参数的类型
ResolvableType[] paramTypes = ResolvableType.forMethodParameter(method, 0);
return paramTypes[0];
}
// 事件派发时
public void onApplicationEvent(ApplicationEvent event) {
ResolvableType eventType = ResolvableType.forInstance(event);
if (supportsEventType(eventType)) {
// 执行监听器逻辑
invokeListener(event);
}
}6.3 GenericConverter 泛型转换
Spring 的类型转换体系在 GenericConverter 中处理泛型集合、Map 等类型的转换:
public interface GenericConverter {
// 获取可转换的类型对
Set<ConvertiblePair> getConvertibleTypes();
// 执行转换,sourceType 和 targetType 携带了完整的泛型信息
Object convert(@Nullable Object source, TypeDescriptor sourceType,
TypeDescriptor targetType);
final class ConvertiblePair {
private final Class<?> sourceType;
private final Class<?> targetType;
// ...
}
}TypeDescriptor 内部封装了 ResolvableType:
public class TypeDescriptor {
private final ResolvableType resolvableType;
private final Class<?> type;
// 创建集合类型的 TypeDescriptor
public static TypeDescriptor collection(Class<?> collectionType,
TypeDescriptor elementTypeDescriptor) {
// 构建 ResolvableType 用于描述 List<String> 等类型
ResolvableType resolvableType = ResolvableType.forClassWithGenerics(
collectionType, elementTypeDescriptor.getResolvableType());
return new TypeDescriptor(resolvableType, null, null);
}
// 获取集合的元素类型
public TypeDescriptor getElementTypeDescriptor() {
ResolvableType elementType = this.resolvableType.asCollection()
.getGeneric(0);
return new TypeDescriptor(elementType, null, null);
}
// 获取 Map 的 Key/Value 类型
public TypeDescriptor getMapKeyTypeDescriptor() {
return new TypeDescriptor(
this.resolvableType.asMap().getGeneric(0), null, null);
}
public TypeDescriptor getMapValueTypeDescriptor() {
return new TypeDescriptor(
this.resolvableType.asMap().getGeneric(1), null, null);
}
}Spring 内置的 CollectionToCollectionConverter 示例:
final class CollectionToCollectionConverter implements ConditionalGenericConverter {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
// 检查是否可以赋值
return ConversionUtils.canConvertElements(
sourceType.getElementTypeDescriptor(),
targetType.getElementTypeDescriptor(),
this.conversionService);
}
@Override
public Object convert(@Nullable Object source, TypeDescriptor sourceType,
TypeDescriptor targetType) {
if (source == null) {
return null;
}
Collection<?> sourceCollection = (Collection<?>) source;
TypeDescriptor elementDesc = targetType.getElementTypeDescriptor();
if (elementDesc == null) {
return sourceCollection;
}
// 逐个元素转换
List<Object> target = new ArrayList<>(sourceCollection.size());
for (Object element : sourceCollection) {
Object converted = this.conversionService.convert(element,
TypeDescriptor.forObject(element), elementDesc);
target.add(converted);
}
// 创建目标集合实例
Collection<Object> result = CollectionFactory.createCollection(
targetType.getType(), target.size());
result.addAll(target);
return result;
}
}7. 源码分析:ResolvableType 类型解析完整流程
7.1 类继承与结构
public class ResolvableType implements Serializable {
// 核心字段
private final Type type; // 持有的 Type 对象
private final ResolvableType[] generics; // 泛型参数数组
private final ResolvableType resolved; // 已解析的类型
private final TypeVariableResolver variableResolver; // 类型变量解析器
// 构造函数(私有,通过静态工厂方法创建)
private ResolvableType(Type type, ResolvableType[] generics,
ResolvableType resolved, TypeVariableResolver variableResolver) {
this.type = type;
this.generics = generics;
this.resolved = resolved;
this.variableResolver = variableResolver;
}
}7.2 forClass() 创建流程
public static ResolvableType forClass(Class<?> clazz) {
// 核心:创建 ResolvableType,使用 DefaultTypeVariableResolver 解析类型变量
return new ResolvableType(
clazz, // type 直接为 Class 对象
null, // generics 为空(后续按需解析)
null, // resolved 为空
null // variableResolver 为 null
);
}7.3 getGeneric() 解析流程
public ResolvableType getGeneric(int... indexes) {
// 获取当前类型的所有泛型参数
ResolvableType[] generics = getGenerics();
if (indexes == null || indexes.length == 0) {
// 无索引,返回所有泛型参数组成的数组类型
return forArray(ResolvableType.class, generics);
}
// 根据索引逐层定位
ResolvableType result = this;
for (int index : indexes) {
ResolvableType[] resolvedGenerics = result.getGenerics();
if (index < 0 || index >= resolvedGenerics.length) {
// 索引越界返回无类型
return NONE;
}
result = resolvedGenerics[index];
}
return result;
}7.4 getGenerics() —— 核心的泛型参数解析
public ResolvableType[] getGenerics() {
if (this == NONE) {
return EMPTY_GENERICS_ARRAY;
}
// 如果已缓存,直接返回
if (this.generics != null) {
return this.generics;
}
// 根据持有的 type 类型分情况处理
if (this.type instanceof Class<?>) {
// 原始 Class 类型:获取类型参数(TypeVariable 数组)
Class<?> clazz = (Class<?>) this.type;
TypeVariable<?>[] typeParams = clazz.getTypeParameters();
ResolvableType[] generics = new ResolvableType[typeParams.length];
for (int i = 0; i < typeParams.length; i++) {
// 为每个 TypeVariable 创建 ResolvableType
generics[i] = new ResolvableType(
typeParams[i],
null, null, this.variableResolver);
}
this.generics = generics;
} else if (this.type instanceof ParameterizedType) {
// 参数化类型:直接从 ParameterizedType 获取
ParameterizedType parameterizedType = (ParameterizedType) this.type;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
ResolvableType[] generics = new ResolvableType[actualTypeArguments.length];
for (int i = 0; i < actualTypeArguments.length; i++) {
generics[i] = new ResolvableType(
actualTypeArguments[i],
null, null, this.variableResolver);
}
this.generics = generics;
} else if (this.type instanceof WildcardType) {
// 通配符类型:提取上边界
this.generics = EMPTY_GENERICS_ARRAY;
} else if (this.type instanceof TypeVariable) {
// 类型变量:尝试解析
ResolvableType resolved = resolveVariable((TypeVariable<?>) this.type);
if (resolved != null) {
this.generics = resolved.getGenerics();
} else {
this.generics = EMPTY_GENERICS_ARRAY;
}
} else if (this.type instanceof GenericArrayType) {
// 泛型数组:委托给组件类型
GenericArrayType arrayType = (GenericArrayType) this.type;
ResolvableType componentType = new ResolvableType(
arrayType.getGenericComponentType(),
null, null, this.variableResolver);
this.generics = componentType.getGenerics();
}
return this.generics;
}7.5 resolve() 解析流程
public Class<?> resolve() {
return resolve(false); // 默认不 fallback 到 TypeVariable
}
public Class<?> resolve(boolean fallbackToVariable) {
if (this.resolved != null) {
return this.resolved;
}
// 根据 type 类型解析为 Class
if (this.type instanceof Class) {
// 直接返回 Class
return (Class<?>) this.type;
} else if (this.type instanceof ParameterizedType) {
// 参数化类型:返回 RawType
ParameterizedType parameterizedType = (ParameterizedType) this.type;
Type rawType = parameterizedType.getRawType();
return (Class<?>) rawType;
} else if (this.type instanceof WildcardType) {
// 通配符类型:返回第一个上边界
WildcardType wildcardType = (WildcardType) this.type;
Type[] upperBounds = wildcardType.getUpperBounds();
if (upperBounds.length > 0) {
// 上边界不为空,转为 ResolvableType 再解析
return forType(upperBounds[0]).resolve();
}
return Object.class;
} else if (this.type instanceof TypeVariable) {
// 类型变量:通过 variableResolver 尝试解析
if (this.variableResolver != null) {
ResolvableType resolved = this.variableResolver.resolveVariable(
(TypeVariable<?>) this.type);
if (resolved != null) {
return resolved.resolve(fallbackToVariable);
}
}
if (fallbackToVariable) {
// fallback:返回第一个边界
TypeVariable<?> typeVariable = (TypeVariable<?>) this.type;
Type[] bounds = typeVariable.getBounds();
if (bounds.length > 0) {
return forType(bounds[0]).resolve(fallbackToVariable);
}
return Object.class;
}
return null;
} else if (this.type instanceof GenericArrayType) {
// 泛型数组
GenericArrayType genericArrayType = (GenericArrayType) this.type;
Type componentType = genericArrayType.getGenericComponentType();
Class<?> componentClass = forType(componentType).resolve(fallbackToVariable);
if (componentClass != null) {
return Array.newInstance(componentClass, 0).getClass();
}
return null;
}
return null;
}7.6 as() 类型转换流程
public ResolvableType as(Class<?> targetType) {
if (this == NONE) {
return NONE;
}
// 如果当前类型就是目标类型,直接返回
if (targetType == getRawClass()) {
return this;
}
// 检查实现的接口
ResolvableType asType = asType(targetType);
if (asType != null) {
return asType;
}
// 检查父类
ResolvableType superType = getSuperType();
if (superType != NONE) {
return superType.as(targetType);
}
return NONE;
}
private ResolvableType asType(Class<?> targetType) {
// 获取当前类型实现的接口
for (ResolvableType ifc : getInterfaces()) {
if (ifc.getRawClass() == targetType) {
return ifc;
}
// 递归检查接口继承
ResolvableType resolved = ifc.asType(targetType);
if (resolved != null) {
return resolved;
}
}
return null;
}7.7 完整解析流程图
forClass(ConcreteClass.class)
│
├── ResolvableType(type = ConcreteClass.class)
│
├── .getSuperType()
│ └── 返回 ResolvableType(ParameterizedType: GenericClass<String, Integer>)
│ ├── .getRawClass() → GenericClass.class
│ └── .getGenerics()
│ ├── [0] ResolvableType(String.class)
│ └── [1] ResolvableType(Integer.class)
│
├── .getGeneric(0).resolve()
│ └── → String.class
│
└── .getGeneric(1).resolve()
└── → Integer.class8. 实战案例:通用 CRUD 基类完整实现
本节实现一套完整的通用 CRUD 基类体系,包括 BaseEntity、BaseRepository、BaseService<T>、BaseController<T>,支持分页、排序和条件查询。
8.1 基础实体类
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Objects;
/**
* 基础实体类,所有实体继承此类
*/
@MappedSuperclass
public abstract class BaseEntity<ID extends Serializable> implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private ID id;
@Column(name = "created_at", updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void prePersist() {
this.createdAt = LocalDateTime.now();
this.updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void preUpdate() {
this.updatedAt = LocalDateTime.now();
}
// getters and setters
public ID getId() {
return id;
}
public void setId(ID id) {
this.id = id;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BaseEntity<?> that = (BaseEntity<?>) o;
return Objects.equals(id, that.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}8.2 实际实体类
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name = "users")
public class User extends BaseEntity<Long> {
@Column(nullable = false, length = 50)
private String username;
@Column(nullable = false, length = 100)
private String email;
@Column(length = 20)
private String phone;
@Column(nullable = false)
private Integer age;
// getters and setters
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}8.3 查询条件封装
import java.util.ArrayList;
import java.util.List;
/**
* 通用查询条件封装
*/
public class QueryCriteria<T> {
private String fieldName;
private Operator operator;
private Object value;
private List<QueryCriteria<T>> children;
private LogicalConnector connector;
public enum Operator {
EQUAL, NOT_EQUAL, LIKE, GREATER_THAN, LESS_THAN,
GREATER_THAN_OR_EQUAL, LESS_THAN_OR_EQUAL, IN, BETWEEN,
IS_NULL, IS_NOT_NULL
}
public enum LogicalConnector {
AND, OR
}
public QueryCriteria() {
this.connector = LogicalConnector.AND;
this.children = new ArrayList<>();
}
public QueryCriteria(String fieldName, Operator operator, Object value) {
this();
this.fieldName = fieldName;
this.operator = operator;
this.value = value;
}
// 静态工厂方法
public static <T> QueryCriteria<T> where(String fieldName, Operator operator, Object value) {
return new QueryCriteria<>(fieldName, operator, value);
}
public QueryCriteria<T> and(QueryCriteria<T> other) {
QueryCriteria<T> parent = new QueryCriteria<>();
parent.connector = LogicalConnector.AND;
parent.children.add(this);
parent.children.add(other);
return parent;
}
public QueryCriteria<T> or(QueryCriteria<T> other) {
QueryCriteria<T> parent = new QueryCriteria<>();
parent.connector = LogicalConnector.OR;
parent.children.add(this);
parent.children.add(other);
return parent;
}
// 构建 JPA Specification
public javax.persistence.criteria.Predicate toPredicate(
jakarta.persistence.criteria.Root<T> root,
jakarta.persistence.criteria.CriteriaQuery<?> query,
jakarta.persistence.criteria.CriteriaBuilder cb) {
if (!children.isEmpty()) {
List<jakarta.persistence.criteria.Predicate> predicates = new ArrayList<>();
for (QueryCriteria<T> child : children) {
predicates.add(child.toPredicate(root, query, cb));
}
return connector == LogicalConnector.AND
? cb.and(predicates.toArray(new jakarta.persistence.criteria.Predicate[0]))
: cb.or(predicates.toArray(new jakarta.persistence.criteria.Predicate[0]));
}
switch (operator) {
case EQUAL:
return cb.equal(root.get(fieldName), value);
case NOT_EQUAL:
return cb.notEqual(root.get(fieldName), value);
case LIKE:
return cb.like(root.get(fieldName), "%" + value + "%");
case GREATER_THAN:
return cb.greaterThan(root.get(fieldName), (Comparable) value);
case LESS_THAN:
return cb.lessThan(root.get(fieldName), (Comparable) value);
case GREATER_THAN_OR_EQUAL:
return cb.greaterThanOrEqualTo(root.get(fieldName), (Comparable) value);
case LESS_THAN_OR_EQUAL:
return cb.lessThanOrEqualTo(root.get(fieldName), (Comparable) value);
case IS_NULL:
return cb.isNull(root.get(fieldName));
case IS_NOT_NULL:
return cb.isNotNull(root.get(fieldName));
default:
throw new UnsupportedOperationException("Unsupported operator: " + operator);
}
}
// getters
public String getFieldName() { return fieldName; }
public Operator getOperator() { return operator; }
public Object getValue() { return value; }
}