spring aop底层代理方式取决于目标类是否实现接口:有接口时默认用jdk动态代理,无接口时强制用cglib;spring 5.2+默认启用objenesis避免调用目标构造器。

Spring AOP底层用的是JDK动态代理还是CGLIB?
取决于目标类是否实现了接口:有接口时默认用 JdkDynamicAopProxy(JDK动态代理),无接口时强制用 ObjenesisCglibAopProxy(CGLIB)。Spring 5.2+ 默认启用 Objenesis 构造代理对象,避免调用目标类构造器——这点常被忽略,导致自定义构造逻辑失效。
可通过配置强制指定:
<!-- 强制使用CGLIB --> <aop:config proxy-target-class="true"/>或 Java Config:
@EnableAspectJAutoProxy(proxyTargetClass = true)
- 接口代理生成的是
$Proxy0这类类名,CGLIB 生成的是Service$$EnhancerBySpringCGLIB$$xxxx - JDK代理只能代理接口方法,CGLIB能代理具体类的非final方法;但final方法、static方法、private方法一律无法被织入
- CGLIB依赖字节码生成,启动稍慢,且不能代理final类;JDK代理无需额外依赖,但要求必须有接口
@Aspect注解的切面类为什么必须由Spring容器管理?
因为 AnnotationAwareAspectJAutoProxyCreator 是一个 BeanPostProcessor,它只在 Spring 容器创建 Bean 的过程中扫描并处理标注了 @Aspect 的 **已注册 Bean**。如果你 new 出来的切面类(比如 new LogAspect()),Spring 根本看不到它,也不会为其生成代理,更不会触发任何通知逻辑。
- 切面类必须是
@Component、@Service或显式@Bean注册的 -
@Aspect本身不带@Component,不加就只是个普通类,不会被识别为切面 - 如果切面类在非Spring上下文(如单元测试中直接 new)里使用,需手动注册到
DefaultListableBeanFactory才可能生效,但通常不推荐
为什么@Before里修改参数,目标方法收不到?
因为 Spring AOP 的通知方法接收到的 JoinPoint 或 ProceedingJoinPoint 中的参数是原始引用副本,@Before 无法拦截并替换实际传入目标方法的参数。只有 @Around 能通过 proceed(Object[] args) 显式传入新参数数组。
@Around("execution(* com.example.service.*.*(..))")
public Object logAndModify(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
// 修改第一个参数
if (args.length > 0 && args[0] instanceof String) {
args[0] = "[MODIFIED]" + args[0];
}
return joinPoint.proceed(args); // 关键:把改过的args传进去
}-
@Before/@After/@AfterReturning都不具备参数重写能力 - 即使参数是可变对象(如
Map、自定义DTO),在@Before里修改其字段是生效的,但这属于对象内部状态变更,不是“替换参数” - 真正想做参数预处理,必须用
@Around,且注意proceed()必须且只能调用一次
同一个Bean内方法调用为什么AOP不生效?
这是最常踩的坑:AOP代理只对**外部调用**生效。如果 serviceA.methodA() 调用本类的 methodB(),走的是 this.methodB(),绕过了代理对象,自然不会触发任何通知。
立即学习“Java免费学习笔记(深入)”;
- 本质是代理模式的局限:Spring注入的是代理对象,但类内部
this指向的是原始对象 - 解决方式有三种:① 把
methodB拆到另一个 Bean;② 通过AopContext.currentProxy()强转后调用(需开启expose-proxy="true");③ 改用@Transactional等声明式注解时,同理也会失效 - 开启暴露代理后,代码变成:
((ServiceA) AopContext.currentProxy()).methodB();
但会破坏封装性,生产环境慎用
Spring AOP 的“透明性”是表象,底层每一步都依赖容器生命周期和代理机制的严格配合;脱离容器、绕过代理、误判调用链路,都会让切面静默失效。










