cglib动态代理不保留泛型方法签名,因其基于字节码生成子类且仅操作擦除后的原始类型;泛型信息需通过反射从具体化父类(如dao)的getgenericsuperclass()中手动提取。

CGLIB 动态代理本身不保留泛型方法签名
CGLIB 通过字节码技术生成目标类的子类来实现代理,它在运行时操作的是擦除后的原始类型。Java 的泛型是编译期特性,经过类型擦除后,所有泛型信息(如 void doSomething(List<string>)</string>)都会变成 void doSomething(List)。CGLIB 无法还原或“保留”泛型签名,因为它不解析泛型元数据,只基于 Class 文件结构生成子类并重写非 final 方法。
泛型信息只能靠反射从继承关系中间接获取
如果你的目标类继承了泛型父类(如 class UserService extends Dao<user></user>),那么泛型实参 User 的类型信息虽已擦除,但可通过反射从子类的 getGenericSuperclass() 中提取——前提是该泛型类型在子类声明中被**具体化**(即未用通配符或变量延迟)。CGLIB 代理对象自身不提供此能力,但你可以在代理逻辑中主动调用:
- 在
MethodInterceptor.intercept()中,通过method.getDeclaringClass()获取目标类 - 再调用
targetClass.getGenericSuperclass()判断是否为ParameterizedType - 从中提取
getActualTypeArguments()[0]得到User.class这类实际类型
方法签名里的泛型参数无法在代理中自动还原
即使你知道父类泛型实参是 User,CGLIB 代理方法的 Method 对象仍显示擦除后的签名。例如:
原始方法:public User findById(Long id)(声明在 Dao<user></user> 中)
运行时 Method#getGenericReturnType() 返回:User(可解析)
但 Method#getParameterTypes() 返回:[class java.lang.Long](无泛型)
而 Method#getGenericParameterTypes() 才可能返回:[java.lang.Long](仍是擦除后,不带泛型上下文)
注意:只有当方法本身声明了泛型参数(如 <t> T convert(Object src)</t>),且调用处明确指定了类型,才可能通过 getGenericReturnType() 或 getGenericParameterTypes() 拿到带类型变量的 Type;但普通继承泛型父类的方法,其签名中的泛型早已固化为原始类型。
真正能“保留”的只有编译期确定的类型实参,不是方法签名本身
所谓“保留”,实际是指你在代理逻辑中可以安全地使用反射拿到父类泛型实参,并据此做类型判断、构造泛型容器或调用特定泛型方法。例如:
- 拦截
save()方法后,根据反射获得的User.class构造new ArrayList<user>()</user> - 对返回值做
type.cast(result)强制类型安全转换 - 配合注解(如
@EntityClass)显式标注类型,绕过反射局限
这需要手动编码支持,CGLIB 不自动完成。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











