jdk动态代理中,方法拦截控制需在invocationhandler.invoke()内通过方法名+参数类型精准识别,推荐用注解@interceptable标记可拦截方法,并对object自带方法、白/黑名单方法等特殊场景做提前处理。

在 JDK 动态代理中,过滤不需要拦截的方法不是靠“跳过代理”,而是通过在 InvocationHandler.invoke() 方法内部做逻辑判断,对特定方法直接放行(不增强)、跳过日志/权限等横切逻辑,甚至绕过目标方法调用。关键在于:代理对象仍会接管所有接口方法调用,但你可以选择“不处理”或“不转发”。
按方法名和参数签名精准识别目标方法
仅靠 method.getName() 容易误判重载方法。必须结合参数类型才能唯一确定是哪个方法:
- 使用
method.getName().equals("xxx") && Arrays.equals(method.getParameterTypes(), new Class[]{String.class, int.class}) - 或更简洁地用
MethodUtils.getMatchingAccessibleMethod(target.getClass(), "xxx", String.class, int.class)(需 Apache Commons Lang) - 避免写成
if ("toString".equals(method.getName())) return "proxy";—— 这会覆盖真实 toString 行为,且未校验是否真的是接口中声明的 toString
白名单/黑名单方式统一控制
适合批量管理。在 InvocationHandler 初始化时传入规则,比如:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
黑名单:记录不希望增强的方法集合(如
hashCode、equals、toString),invoke 中先检查是否命中,命中则直调method.invoke(target, args)不加日志 -
白名单:只对明确标注
@Log或@Audit的方法执行增强逻辑,其余一律透传 - 建议用
Set<string></string>存方法签名(如"save-java.lang.String-int"),比每次拼接更高效
利用注解标记可拦截方法
比字符串匹配更安全、更语义化。定义一个自定义注解:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Interceptable {}然后在 invoke 中检查:
if (!method.isAnnotationPresent(Interceptable.class)) { return method.invoke(target, args); }- 这样既清晰表达了设计意图,又避免硬编码方法名,后续增删方法无需改拦截器逻辑
- 注意:注解必须作用在接口方法上(而非实现类),因为代理调用的是接口契约
跳过代理调用的特殊情况
某些方法根本不该走代理链,比如:
-
Object自带方法(getClass()、wait()等)——JVM 规定它们不能被代理重写,调用时会抛IllegalArgumentException;应提前拦截并抛出明确提示 - 空方法体或纯 getter(如
getName())——若无业务意义,可直接返回默认值或缓存结果,不触发method.invoke() - 性能敏感方法(如高频
size())——可在 invoke 中做短路返回,避免反射开销
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










