接口默认方法在 Spring AOP 中默认不会被拦截,因 JDK 动态代理不重写默认方法,调用直接委托目标对象,绕过 AOP 拦截链;仅当实现类显式重写该方法时才可被增强。

接口默认方法在 Spring AOP 中**默认不会被拦截**,这是由 Spring AOP 的代理机制决定的,不是配置遗漏或写法错误,而是底层原理限制。
为什么默认方法不被拦截?
Spring AOP 依赖动态代理(JDK Proxy 或 CGLIB)实现增强。而 JDK 动态代理生成的代理类只实现接口,不继承实现类,但关键点在于:代理对象本身不提供默认方法的具体实现——它只是把调用原样转发给目标对象(即实现类实例)。而 Spring AOP 的切点匹配发生在代理层的 invoke() 方法中,仅对代理对象“显式实现”的方法生效;接口默认方法在代理类中并未被重写,调用时直接委托给目标对象执行,绕过了 AOP 的拦截链。
换句话说:默认方法的逻辑实际在实现类里运行,但代理对象没有为它注册拦截器,所以通知(Advice)不会触发。
哪些情况能触发拦截?
只有当默认方法的调用路径经过代理对象的 invoke() 入口时,才可能被织入。这需要满足两个条件:
立即学习“Java免费学习笔记(深入)”;
- 目标类通过接口引用被调用(例如
UserService service = context.getBean(UserService.class); service.doSomething();) - 该方法在实现类中未被重写(即直接使用接口默认实现)
即便如此,JDK 动态代理仍不会为默认方法生成拦截逻辑——因为 Proxy 生成的代理类字节码中,对该方法的处理是直接调用 super.method()(指向接口默认实现),而非走 AOP 的 MethodInvocation.proceed() 流程。
如何让默认方法也被增强?
目前没有开箱即用的纯注解方案,但有几种可行路径:
-
在实现类中显式重写默认方法:哪怕只写一行
super.xxx(),也能让它变成“目标类自己的方法”,从而被正常拦截 - 改用 CGLIB 代理:对无接口或需代理类内部方法的场景更友好,但注意——CGLIB 代理的是具体类,而接口默认方法不属于类的成员,CGLIB 同样无法拦截(除非重写)
- 避免依赖接口默认方法做核心横切逻辑:把需要 AOP 增强的逻辑放在普通业务方法里,保持默认方法仅作轻量委托或兼容性封装
验证方式很简单
写个切面,切点用 @Pointcut("execution(* com.example.service..*.*(..))"),然后在接口定义默认方法、实现类不重写它,再调用测试——你会发现前置/环绕通知完全不触发。一旦在实现类里加 @Override public void xxx() { super.xxx(); },立刻就能拦截到。


















