泛型不参与动态代理运行时逻辑,但通过泛型接口约束目标类型、泛型Handler持有强类型target,提升类型安全与复用性;配合接口声明和注解,实现编译期校验、避免强制转换、支持语义化扩展。

泛型本身不直接参与动态代理的运行时逻辑,但可以显著提升 InvocationHandler 的类型安全性和复用性——关键在于:用泛型接口约束目标对象类型,再通过泛型参数把业务对象“包装”进 handler,避免强制转换和类型丢失。
泛型接口定义目标契约
先定义一个泛型业务接口,明确方法签名与返回类型:
示例:
public interface ServiceT process(String input);
void log(String msg);
}
这个接口不是为了被代理“实现”,而是作为 target 对象必须遵守的契约。它让 handler 能在编译期就知道目标方法的返回类型是 T,后续处理更精准。
泛型 InvocationHandler 持有强类型 target
handler 类自身声明泛型参数,并用 private final T target 持有业务对象:
示例:
public class GenericServiceHandlerprivate final T target;
private final Class
public GenericServiceHandler(T target, Class
this.target = target;
this.targetType = targetType;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("process".equals(method.getName())) {
// 编译期已知返回类型为 T,可安全接收
Object result = method.invoke(target, args);
return enhanceResult(result); // 返回值类型与 T 一致
}
return method.invoke(target, args);
}
}
这样写的好处:
- target 字段是
T类型,IDE 和编译器能校验调用合法性 - 避免在
invoke中反复写(Service这类易错转换) target - 配合
Class参数,可在运行时做类型检查或泛型桥接方法识别
创建代理时传入具体泛型实例
使用时指定真实类型,让整个链条保持类型一致:
示例:
ServiceInvocationHandler handler = new GenericServiceHandler(realService, Service.class);
Service
realService.getClass().getClassLoader(),
new Class[]{Service.class},
handler
);
String result = proxy.process("hello"); // 返回值自动推导为 String,无装箱/拆箱风险
注意:Proxy.newProxyInstance 不感知泛型(因类型擦除),但接口变量声明 Service 提供了编译期类型保障,调用链不会断。
泛型 + 注解增强可读性与扩展性
可在泛型接口方法上加自定义注解,handler 中结合泛型类型提取语义:
示例:
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)
public @interface Cacheable {
String key() default "";
}
public interface UserService extends Service
@Cacheable(key = "user:{id}")
User getById(Long id);
}
handler 中可通过 method.getAnnotation(Cacheable.class) 获取配置,并利用 T 类型知道缓存值应反序列化为 User 实例,无需硬编码类型转换。











