侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

Spring AOP中JDK动态代理与CGLIB代理的区别及使用场景

2025-12-5 / 0 评论 / 4 阅读

题目

Spring AOP中JDK动态代理与CGLIB代理的区别及使用场景

信息

  • 类型:问答
  • 难度:⭐⭐

考点

代理机制理解,JDK动态代理与CGLIB区别,Spring AOP配置原理

快速回答

核心要点:

  • JDK动态代理基于接口,通过Proxy类创建代理对象,要求目标类实现接口
  • CGLIB代理通过字节码增强生成目标类的子类作为代理,无需接口
  • Spring默认优先使用JDK动态代理,无接口时自动切换CGLIB
  • 强制使用CGLIB需配置@EnableAspectJAutoProxy(proxyTargetClass=true)
## 解析

一、代理机制原理

Spring AOP 通过代理模式实现切面功能:

  • JDK动态代理:基于Java反射API,运行时动态生成实现目标接口的代理类
  • CGLIB代理:通过ASM字节码操作库,生成目标类的子类并重写方法

二、核心区别对比

特性JDK动态代理CGLIB代理
依赖要求目标类必须实现接口无需接口,可代理普通类
代理对象类型实现相同接口的新类目标类的子类
性能表现创建快,执行稍慢创建慢(需字节码生成),执行快
final方法限制无限制无法代理final方法/类

三、代码示例

JDK代理使用示例:

public interface UserService {
    void saveUser();
}

public class UserServiceImpl implements UserService {
    @Override
    public void saveUser() {
        System.out.println("保存用户");
    }
}

// Spring自动创建代理(需接口)
@Autowired
private UserService userService; // 实际为Proxy实例

CGLIB代理配置:

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用CGLIB
public class AppConfig {}

四、使用场景建议

  • 优先JDK动态代理:业务类已实现接口时(符合面向接口编程原则)
  • 必须CGLIB
    • 代理未实现接口的类
    • 需要代理非public方法
    • 目标对象被多次代理(避免JDK代理嵌套问题)

五、常见错误

  • 错误1:对未实现接口的类未配置proxyTargetClass,导致代理失败
  • 错误2:在代理类中调用内部方法(this.xxx())绕过切面,应通过AopContext获取代理对象
  • 错误3:尝试代理final方法(CGLIB会忽略切面)

六、扩展知识

  • 性能优化:Spring 4.x后CGLIB创建性能大幅提升,差距缩小
  • Objenesis库:CGLIB通过该库跳过构造函数创建代理实例
  • Spring Boot默认:2.x版本开始默认使用CGLIB(因多数场景无接口)