Skip to content

02.1 — JDK 动态代理与 CGLIB

定位: Spring AOP 的两种代理实现方式——原理、对比与选择策略 面试高频度: ⭐⭐⭐⭐⭐ 考查方式: 两种代理原理、Spring 选择策略、代码实现

一、这是什么?为什么需要它?

Spring AOP 需要在不修改目标类代码的情况下为方法增强。这通过代理模式实现——创建一个"代理对象"包裹目标对象,在代理对象中插入增强逻辑。

Spring 提供了两种代理方式:JDK 动态代理(基于接口)和 CGLIB(基于继承)。

二、原理拆解

2.1 对比

特性JDK 动态代理CGLIB 代理
原理基于接口,生成实现类基于继承,生成子类
目标要求必须实现接口无接口也可
速度创建快,调用稍慢创建慢(需生成字节码),调用快
限制只能代理接口方法final 类/方法无法代理
依赖JDK 内置需要 asm 字节码库

2.2 Spring 选择策略

Spring 决定代理方式
    -> 目标 Bean 是否实现接口?
    -> 是 -> 是否配置 proxyTargetClass=true?
        -> 否 -> JDK 动态代理
        -> 是 -> CGLIB 代理
    -> 否 -> CGLIB 代理
    -> 目标类是否 final?
        -> 是 -> 抛出异常,无法代理

Spring Boot 2.0+ 默认:spring.aop.proxy-target-class=true,优先使用 CGLIB。

2.3 代码示例

java
// JDK 动态代理
public class JdkProxyHandler implements InvocationHandler {
    private final Object target;
    
    public JdkProxyHandler(Object target) { this.target = target; }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before: " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("After: " + method.getName());
        return result;
    }
    
    public static <T> T createProxy(T target, Class<T> interfaceType) {
        return (T) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            new Class[]{interfaceType},
            new JdkProxyHandler(target)
        );
    }
}

// CGLIB 代理
public class CglibProxyInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) 
            throws Throwable {
        System.out.println("Before: " + method.getName());
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After: " + method.getName());
        return result;
    }
    
    public static <T> T createProxy(Class<T> targetClass) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetClass);
        enhancer.setCallback(new CglibProxyInterceptor());
        return (T) enhancer.create();
    }
}

三、面试视角

追问答案要点
JDK 动态代理和 CGLIB 各自的实现原理?JDK: 接口-based, Proxy.newProxyInstance;CGLIB: 继承-based, Enhancer+MethodProxy
Spring 如何选择代理方式?有接口用 JDK,无接口用 CGLIB;Spring Boot 默认用 CGLIB
CGLIB 能代理 final 类吗?不能,CGLIB 基于继承生成子类,final 类无法被继承
JDK 动态代理为什么调用慢?JDK 基于反射(Method.invoke),CGLIB 基于 FastClass 索引调用

📚 相关链接

  • **AOP核心概念** — 代理的上层应用
  • **@Transactional原理** — 声明式事务的代理基础
  • **Bean生命周期** — AOP 代理在 postProcessAfterInitialization 生成
  • ← 返回 **返回 AOP 索引**

Knowledge4J — Java 知识库