JDK 动态代理 vs CGLIB 动态代理

JDK 动态代理和 CGLIB 动态代理是 Spring AOP 以及许多 Java 框架中常见的两种动态代理方式,它们在实现方式、使用场景和性能上有所不同。

JDK 动态代理

特点

  • 依赖 java.lang.reflect.ProxyInvocationHandler 进行代理
  • 只能代理接口,不能直接代理具体类
  • 基于 Java 反射,在运行时生成代理类

实现方式

  1. 目标类必须实现 接口
  2. 使用 Proxy.newProxyInstance() 生成代理对象
  3. 代理方法调用时,委托给 InvocationHandler 处理
import java.lang.reflect.*;

interface Service {
    void doSomething();
}

class RealService implements Service {
    public void doSomething() {
        System.out.println("真实业务逻辑执行");
    }
}

class MyInvocationHandler implements InvocationHandler {
    private final Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDK 代理 - 方法执行前");
        Object result = method.invoke(target, args);
        System.out.println("JDK 代理 - 方法执行后");
        return result;
    }
}

public class JDKProxyTest {
    public static void main(String[] args) {
        Service target = new RealService();
        Service proxy = (Service) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new MyInvocationHandler(target)
        );

        proxy.doSomething();
    }
}

运行结果

JDK 代理 - 方法执行前
真实业务逻辑执行
JDK 代理 - 方法执行后

优缺点

优点:

  • 基于 JDK 反射,不依赖第三方库,性能较稳定
  • 避免类加载问题(无需操作字节码)
  • 支持多个接口的代理

缺点:

  • 只能代理接口,不能代理普通类
  • 性能比 CGLIB 稍低(JDK 代理基于反射,CGLIB 直接使用字节码增强)

CGLIB 动态代理

特点

  • 依赖 ASM 字节码技术,通过继承目标类创建子类代理
  • 可以代理普通类(不需要实现接口)
  • 基于子类代理,无法代理 final 类或 final 方法

实现方式

  1. 目标类不需要接口
  2. CGLIB 生成子类代理对象
  3. 拦截方法调用并增强逻辑
import net.sf.cglib.proxy.*;

class RealService {
    public void doSomething() {
        System.out.println("真实业务逻辑执行");
    }
}

class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("CGLIB 代理 - 方法执行前");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("CGLIB 代理 - 方法执行后");
        return result;
    }
}

public class CGLIBProxyTest {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealService.class);
        enhancer.setCallback(new MyMethodInterceptor());

        RealService proxy = (RealService) enhancer.create();
        proxy.doSomething();
    }
}

运行结果

CGLIB 代理 - 方法执行前
真实业务逻辑执行
CGLIB 代理 - 方法执行后

优缺点

优点:

  • 可以代理普通类,不要求实现接口
  • 性能比 JDK 代理更高(直接操作字节码,无需反射)

缺点:

  • 无法代理 final 类和 final 方法
  • 生成代理类耗时更长(类字节码需要动态修改)
  • 需要额外依赖 CGLIB(Spring 3.2 以前),Spring 4+ 自带 ByteBuddy 作为替代

JDK 动态代理 vs CGLIB 动态代理

对比项JDK 动态代理CGLIB 动态代理
实现方式反射(Proxy + InvocationHandler继承(字节码增强 Enhancer
是否需要接口需要(只能代理接口)不需要(可代理普通类)
性能反射调用,性能略低直接调用字节码,性能更高
是否支持 final 类支持不支持
Spring AOP 代理方式默认使用(若有接口)无接口时使用
应用场景代理接口服务(如 RPC、Spring AOP)需要代理普通类(如 MyBatis)

Spring AOP 选择哪种代理?

Spring AOP 默认选择 JDK 动态代理,除非目标类没有实现接口,才会使用 CGLIB:

  • 有接口 → JDK 代理(默认)
  • 无接口 → CGLIB 代理

如果希望 Spring 强制使用 CGLIB,可以:

@EnableAspectJAutoProxy(proxyTargetClass = true)

在实际开发中:

  • 如果业务主要是接口编程(如 Service 层),JDK 代理更合适
  • 如果需要代理普通类(如工具类),CGLIB 是更好的选择

两者各有优势,选择合适的方式能提升代理的效率和可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值