一、先搞清楚两种代理的核心差异

1.1 JDK 动态代理(默认
// 原理:基于接口public interface IOrderService {    void createOrder(Order order);  // 必须是接口}// 代理实现public class OrderServiceProxy implements IOrderService {    private IOrderService target;  // 持有目标对象        public void createOrder(Order order) {        // 1. 开启事务        // 2. 调 target.createOrder(order)        // 3. 提交或回滚    }}

JDK 代理限制:

  • 只能代理接口方法(public abstract)
  • private / protected / final / static 方法 全部代理不到
  • 同类内 this 调用也不走代理
1.2 CGLIB 代理(继承式
// 原理:基于继承public class OrderService {  // 不需要接口    public void createOrder(Order order) { ... }    private void privateMethod() { ... }  // CGLIB 能代理 private}// CGLIB 生成的子类public class OrderService$$EnhancerByCGLIB$$xxx extends OrderService {    public void createOrder(Order order) {        // 1. 开启事务        // 2. 调 super.createOrder(order)        // 3. 提交或回滚    }        private void privateMethod() {  // ✅ CGLIB 能代理        // 1. 开启事务        // 2. 调 super.privateMethod()    }}

CGLIB 优势:

  • 不需要接口,直接继承类
  • 能代理 private / protected 方法(生成子类重写)
  • 能代理 package-private 方法

CGLIB 限制:

  • 不能代理 final 方法(不能重写 final)
  • 不能代理 static 方法(属于类,不属于实例)
  • 同类内 this 调用仍然不走代理(super 调用绕过代理对象)

二、CGLIB 能解决哪些事务失效问题?

2.1 CGLIB 能解决的(主要是方法可见性问题
场景 JDK 代理 CGLIB 代理 解决?
private 方法 ❌ 代理不到 ✅ 能代理
protected 方法 ❌ 代理不到 ✅ 能代理
package-private 方法 ❌ 代理不到 ✅ 能代理
final 方法 ❌ 代理不到 ❌ 也不能代理(CGLIB 不能重写 final)
static 方法 ❌ 代理不到 ❌ 也不能代理
2.2 CGLIB 解决不了的(事务失效核心问题
场景 JDK 代理 CGLIB 代理 解决?
异常自己 catch 住 ❌ 失效 ❌ 失效 ❌ CGLIB 也救不了
抛检查异常没配 rollbackFor ❌ 失效 ❌ 失效
同类 this 调用 ❌ 失效 ❌ 失效
@Transactional 在接口上 ❌ 失效 ⚠️ 部分解决(直接代理实现类) ⚠️
@Async 异步 ❌ 失效 ❌ 失效
多线程调用 ❌ 失效 ❌ 失效
AOP 顺序 ❌ 失效 ❌ 失效

核心结论:

  • CGLIB 只解决"方法可见性"问题(private / protected)
  • 事务失效的 80% 问题是"异常处理"和"调用方式",CGLIB 帮不了

三、Spring 怎么配置 CGLIB 代理?

3.1 Spring Boot 2.x+(老哥项目一般用这个
@Configuration@EnableAspectJAutoProxy(proxyTargetClass = true)  // ✅ 强制 CGLIBpublic class AppConfig {}

或者 application.yml:

spring:  aop:    proxy-target-class: true  # ✅ Spring Boot 配置

Spring Boot 2.x 默认就是 CGLIB 代理!(Spring Boot 1.x 是 JDK)

3.2 验证当前项目是不是 CGLIB
@SpringBootApplicationpublic class DemoApplication {    public static void main(String[] args) {        ConfigurableApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);                OrderService bean = ctx.getBean(OrderService.class);        System.out.println(bean.getClass().getName());        // 输出:com.niejq.demo.OrderService$$EnhancerByCGLIB$$xxx        // ✅ CGLIB 代理    }}
3.3 老哥项目验证

老哥你的赢时胜 mpvs 项目:Spring Cloud + Spring Boot 2.x → 默认 CGLIB 代理老哥你的 DLQ Demo:Spring Boot 3.2.5 → 默认 CGLIB 代理

所以老哥你项目里 @Transactional 默认就在 CGLIB 代理上跑,private 方法理论上能代理(但业务里很少写 private 事务方法)。

四、CGLIB 解决不了的事务失效,怎么破?

4.1 异常被吃 → 手动回滚
@Servicepublic class OrderService {        @Transactional    public void createOrder(Order order) {        try {            orderDao.insert(order);            accountDao.debit(order.getAccountId(), order.getAmount());        } catch (Exception e) {            // 手动回滚(不管 JDK 还是 CGLIB 都得这么干)            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();            throw new BusinessException("订单创建失败", e);        }    }}
4.2 检查异常 → rollbackFor
@Transactional(rollbackFor = Exception.class)  // 不管什么代理都得配public void createOrder(Order order) throws IOException {    // ...}
4.3 this 调用 → 注入 self
@Servicepublic class OrderService {        @Autowired    private OrderService self;  // 注入自己        public void createOrder(Order order) {        self.updateOrder(order);  // ✅ 走代理(CGLIB 也得这么干)    }        @Transactional    public void updateOrder(Order order) {        // CGLIB 也会拦截到    }}
4.4 @Async 失效 → 拆成两个 Bean
@Servicepublic class OrderService {        @Autowired    private AsyncTaskService asyncTask;  // 拆出去        public void createOrder(Order order) {        asyncTask.doAsync(order);  // ✅ 异步任务是另一个 Bean,走代理    }}@Servicepublic class AsyncTaskService {        @Async    @Transactional    public void doAsync(Order order) {        orderDao.insert(order);    }}

五、CGLIB vs JDK 代理完整对比

维度 JDK 代理 CGLIB 代理
实现方式 接口 继承类
需要接口 ✅ 必须 ❌ 不需要
private 方法 ❌ 代理不到 ✅ 能代理
protected 方法 ❌ 代理不到 ✅ 能代理
final 方法 ❌ 代理不到 ❌ 不能重写
static 方法 ❌ 代理不到 ❌ 不能拦截
同类 this 调用 ❌ 不走代理 ❌ 不走代理
性能 略快(反射) 略慢(生成子类)
Spring Boot 2.x+ 默认 ❌ 默认 CGLIB ✅ 默认 CGLIB
启动时间 略慢(生成代理类)

六、面试官追问应对(老哥 30 秒杀手锏

追问:Spring 默认是 JDK 代理还是 CGLIB 代理?

"Spring Boot 2.x+ 默认 CGLIB 代理,因为现在大部分类没有接口(Spring 推荐面向对象而非接口编程)。

Spring 1.x / 传统 Spring 是 JDK 代理(基于接口),如果项目有接口会用 JDK,没有就用 CGLIB。

强制 CGLIB 代理@EnableAspectJAutoProxy(proxyTargetClass = true)spring.aop.proxy-target-class: true"

追问:CGLIB 代理能解决事务失效的所有问题吗?

"不能。CGLIB 只解决'方法可见性'问题(private / protected),事务失效的核心 3 大原因(异常被吃、检查异常、this 调用)CGLIB 都救不了

解决方式:

1.异常被吃 → 手动 setRollbackOnly() 或抛出

2.检查异常 → rollbackFor = Exception.class

3.this 调用 → 注入 self

    **CGLIB 只是工具,事务传播规则是根本,**不要迷信配置代理方式能解决所有问题。"

    追问:怎么知道当前 Bean 是 JDK 还是 CGLIB 代理?
    OrderService bean = ctx.getBean(OrderService.class);System.out.println(bean.getClass().getName());// JDK 代理:com.sun.proxy.$Proxy123// CGLIB 代理:com.niejq.demo.OrderService$$EnhancerByCGLIB$$xxx

    记忆口诀

    "CGLIB 解决 private,救不了异常吃了"

    "JDK 代理只能 public,CGLIB 代理能 private,但 final/static 都不行"

    "this 调用 JDK 和 CGLIB 都不走代理,注入 self 才安全"

    "Spring Boot 2.x 默认 CGLIB 代理,proxy-target-class 强制开启"

    "事务失效改代码,不要迷信改代理"

    Logo

    汇聚全球AI编程工具,助力开发者即刻编程。

    更多推荐