导读:本期聚焦于小伙伴创作的《Java动态代理性能压测:JDK代理与CGLIB代理在变量处理上对比怎么样》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Java动态代理性能压测:JDK代理与CGLIB代理在变量处理上对比怎么样》有用,将其分享出去将是对创作者最好的鼓励。

Java动态代理是面向切面编程、方法增强等场景的核心技术实现,JDK代理和CGLIB代理作为两种主流实现方式,在变量处理的逻辑和性能表现上有明显区别,本文通过压测来对比二者的差异。

Java动态代理性能压测:JDK代理与CGLIB代理在变量处理上对比怎么样

两种代理的核心原理

JDK代理是基于接口实现的动态代理,它要求被代理的类必须实现至少一个接口,代理对象会实现相同的接口,方法调用时通过反射调用被代理对象的方法,变量处理时会依托接口定义的参数类型进行传递。

CGLIB代理是基于继承实现的动态代理,它通过生成被代理类的子类来创建代理对象,不需要被代理类实现接口,变量处理时可以直接操作子类中继承的父类变量,也可以通过方法重写修改变量传递逻辑。

压测环境准备

本次压测使用的环境配置如下:

  • JDK版本:1.8
  • CGLIB版本:3.3.0
  • 压测工具:JMH
  • 测试场景:代理方法中修改变量值、传递复杂对象变量、批量处理变量三种场景

被代理接口与类定义

首先定义JDK代理需要的接口和CGLIB代理需要的普通类,二者包含相同的变量处理方法:

// JDK代理使用的接口
public interface UserService {
    String processVar(String input, int count);
    User updateUser(User user);
}

// CGLIB代理使用的普通类
public class UserServiceCglib {
    public String processVar(String input, int count) {
        return input + count;
    }
    
    public User updateUser(User user) {
        user.setAge(user.getAge() + 1);
        return user;
    }
}

// 公共变量类
public class User {
    private String name;
    private int age;
    
    // 省略getter、setter和构造方法
}

代理实现代码

分别实现JDK代理和CGLIB代理的逻辑,保证二者除了代理实现方式不同,变量处理的业务逻辑完全一致:

// JDK代理实现
public class JdkProxy implements InvocationHandler {
    private Object target;
    
    public JdkProxy(Object target) {
        this.target = target;
    }
    
    public Object createProxy() {
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            this
        );
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 变量处理:如果是processVar方法,修改第二个参数的值
        if ("processVar".equals(method.getName()) && args != null && args.length > 1) {
            args[1] = (int)args[1] * 2;
        }
        // 如果是updateUser方法,修改传入的User对象的name
        if ("updateUser".equals(method.getName()) && args != null && args.length > 0) {
            User user = (User) args[0];
            user.setName(user.getName() + "_jdk");
        }
        return method.invoke(target, args);
    }
}

// CGLIB代理实现
public class CglibProxy implements MethodInterceptor {
    private Object target;
    
    public CglibProxy(Object target) {
        this.target = target;
    }
    
    public Object createProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // 变量处理:和JDK代理保持相同的逻辑
        if ("processVar".equals(method.getName()) && args != null && args.length > 1) {
            args[1] = (int)args[1] * 2;
        }
        if ("updateUser".equals(method.getName()) && args != null && args.length > 0) {
            User user = (User) args[0];
            user.setName(user.getName() + "_cglib");
        }
        return proxy.invoke(target, args);
    }
}

压测方案设计

本次压测分三个场景进行,每个场景执行5次预热,然后执行10次正式测试,取平均结果:

  • 场景1:简单变量处理,调用processVar方法,传入字符串和整数变量,统计平均响应时间和吞吐量
  • 场景2:复杂对象变量处理,调用updateUser方法,传入User对象,统计平均响应时间和吞吐量
  • 场景3:批量变量处理,循环调用1000次processVar方法,统计总耗时和内存占用情况

JMH压测代码示例

@BenchmarkMode(Mode.Throughput)
@Warmup(iterations = 5)
@Measurement(iterations = 10)
@Threads(8)
@Fork(2)
public class ProxyBenchmark {
    private UserService jdkProxy;
    private UserServiceCglib cglibProxy;
    private User testUser;
    
    @Setup
    public void setup() {
        // 初始化JDK代理
        UserService userService = new UserServiceImpl();
        JdkProxy jdkHandler = new JdkProxy(userService);
        jdkProxy = (UserService) jdkHandler.createProxy();
        
        // 初始化CGLIB代理
        UserServiceCglib userServiceCglib = new UserServiceCglib();
        CglibProxy cglibHandler = new CglibProxy(userServiceCglib);
        cglibProxy = (UserServiceCglib) cglibHandler.createProxy();
        
        testUser = new User("test", 20);
    }
    
    @Benchmark
    public void testJdkSimpleVar() {
        jdkProxy.processVar("hello", 10);
    }
    
    @Benchmark
    public void testCglibSimpleVar() {
        cglibProxy.processVar("hello", 10);
    }
    
    @Benchmark
    public void testJdkComplexVar() {
        jdkProxy.updateUser(new User("test", 20));
    }
    
    @Benchmark
    public void testCglibComplexVar() {
        cglibProxy.updateUser(new User("test", 20));
    }
    
    @Benchmark
    public void testJdkBatchVar() {
        for (int i = 0; i < 1000; i++) {
            jdkProxy.processVar("hello", i);
        }
    }
    
    @Benchmark
    public void testCglibBatchVar() {
        for (int i = 0; i < 1000; i++) {
            cglibProxy.processVar("hello", i);
        }
    }
}

压测结果对比

三个场景的压测结果如下,吞吐量单位为每秒操作次数,响应时间为纳秒:

测试场景代理类型吞吐量(ops/s)平均响应时间(ns)内存占用(MB)
简单变量处理JDK代理1250006412
CGLIB代理980008118
复杂对象变量处理JDK代理1120007115
CGLIB代理1050007620
批量变量处理JDK代理980008222
CGLIB代理1020007825

结果分析

从压测结果可以看出,两种代理在变量处理上的表现各有优劣:

  • 简单变量和复杂对象变量处理场景下,JDK代理的吞吐量更高,响应时间更短,因为JDK代理基于接口反射调用,变量类型在编译期已经确定,不需要额外的字节码操作开销。
  • 批量变量处理场景下,CGLIB代理的吞吐量略高于JDK代理,因为CGLIB生成的代理类是子类,方法调用时不需要像JDK代理那样每次都通过反射调用,批量场景下反射的额外开销会更明显。
  • 内存占用方面,JDK代理的内存占用始终低于CGLIB代理,因为CGLIB需要生成额外的子类字节码,会占用更多的元空间内存。

选型建议

根据压测结果,在实际开发中可以参考以下选型规则:

  • 如果被代理类已经实现了接口,且变量处理逻辑简单,优先选择JDK代理,能获得更好的性能和更低的内存占用。
  • 如果被代理类没有实现接口,或者需要频繁进行批量变量处理操作,可以选择CGLIB代理,避免反射带来的性能损耗。
  • 如果系统对内存占用比较敏感,且变量处理场景不复杂,优先选择JDK代理。
需要注意的是,CGLIB代理无法代理被final修饰的类和方法,因为它无法生成对应类的子类,而JDK代理没有这个限制,只要类实现了接口即可使用。

在实际开发中,还可以通过缓存代理对象、减少不必要的变量修改操作等方式,进一步提升动态代理在变量处理场景下的性能表现。

Java动态代理JDK代理CGLIB代理变量处理性能压测修改时间:2026-06-10 14:48:37

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。