拦截器模式通过定义统一接口(如preIntercept、postIntercept、shouldProceed)并结合动态代理(JDK/CGLIB)实现无侵入方法调用过滤;支持按类名、方法名、参数、注解及配置动态决策,需规避耗时操作、异常丢失、不可代理方法等陷阱。

直接用接口实现拦截器模式,核心是定义统一的拦截契约,再通过代理对象在方法调用前后插入逻辑——不改原类、不侵入业务,就能对任意对象的方法调用做动态过滤。
明确拦截器接口设计
先定义一个标准拦截入口,比如 Java 中常用 HandlerInterceptor 或自定义接口:
- 接口应包含 preIntercept(调用前)、postIntercept(调用后)、shouldProceed(是否放行)等语义清晰的方法
- 参数需覆盖目标对象、方法名、入参数组、返回值占位(便于修改)、异常捕获上下文
- 返回值类型建议为布尔或枚举,明确表达“继续执行”“跳过”“抛异常”等意图
用动态代理包装目标对象
Java 可用 JDK 动态代理(仅支持接口)或 CGLIB(支持类),.NET 可用 Castle DynamicProxy。关键不是“写死逻辑”,而是把拦截器实例传给代理工厂:
- JDK 示例:实现 InvocationHandler,在 invoke() 中调用拦截器的 preIntercept(),再根据返回值决定是否执行 method.invoke(target, args)
- CGLIB 示例:继承 MethodInterceptor,重写 intercept(),手动控制 proceed() 的时机
- 注意:代理对象必须和原始对象类型兼容,否则调用方无法无感替换
按变量/方法特征做条件过滤
所谓“对对象变量的方法调用进行动态过滤”,本质是运行时判断——不能靠编译期硬编码:
- 在 preIntercept() 中检查 target.getClass().getSimpleName() 或字段注解(如 @Sensitive)决定是否拦截
- 根据 method.getName() 和 args 内容做规则匹配,例如:“当调用 setPassword() 且参数含明文时拒绝”
- 结合 Spring 的 @Value("${feature.enable-logging:true}") 或配置中心,让开关可热更新
避免常见陷阱
看似简单,但实际落地容易踩坑:
- 不要在拦截器里做耗时操作(如远程调用),否则拖慢所有被代理方法;异步记录日志更稳妥
- 确保 postIntercept() 能拿到真实返回值或异常,尤其涉及事务或重试逻辑时
- 静态工具类、final 方法、private 方法无法被常规代理拦截,需换用字节码增强(如 ByteBuddy)或编译期源生成
- 多个拦截器叠加时,明确执行顺序(如用 @Order 或链式调用),避免漏执行或重复执行










