Cglib 与 JDK动态代理的运行性能比较
都说 Cglib 创建的动态代理的运行性能比 JDK 动态代理能高出大概 10 倍,验证了一下
引入maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.20</version>
</dependency>
代码很简单,首先,定义一个 Test 接口,和一个实现 TestImpl 。Test 接口仅定义一个方法 test,对传入的 int 参数加 1 后返回。代码如下:
package com.hitd;
/**
* @Author ZhangWeinan
* @Date 2022/11/3 15:10
* @DES
* @Since Copyright(c)
*/
public interface Test {
public int test(int i);
}
package com.hitd;
/**
* @Author ZhangWeinan
* @Date 2022/11/3 15:10
* @DES
* @Since Copyright(c)
*/
public class TestImpl implements Test{
public int test(int i) {
return i+1;
}
}
然后,定义了三种代理的实现:静态代理代理(static),JDK 动态代理(dynamic proxy) 和 Cglib 动态代理 (cglib proxy)。代码如下:
package com.hitd;
/**
* @Author ZhangWeinan
* @Date 2022/11/3 15:10
* @DES
* @Since Copyright(c)
*/
public class StaticTest implements Test{
private Test target;
public StaticTest(Test target) {
this.target = target;
}
public int test(int i) {
return target.test(i);
}
}
package com.hitd;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Author ZhangWeinan
* @Date 2022/11/3 15:10
* @DES
* @Since Copyright(c)
*/
public class DynamicProxyTest implements InvocationHandler {
private Test target;
private DynamicProxyTest(Test target) {
this.target = target;
}
public static Test newProxyInstance(Test target) {
return (Test) Proxy
.newProxyInstance(DynamicProxyTest.class.getClassLoader(),
new Class<?>[] { Test.class },
new DynamicProxyTest(target));
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return method.invoke(target, args);
}
}
package com.hitd;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @Author ZhangWeinan
* @Date 2022/11/3 15:10
* @DES
* @Since Copyright(c)
*/
public class CglibProxyTest implements MethodInterceptor {
private CglibProxyTest() {
}
public static <T extends Test> Test newProxyInstance(Class<T> targetInstanceClazz){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetInstanceClazz);
enhancer.setCallback(new CglibProxyTest());
return (Test) enhancer.create();
}
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
return proxy.invokeSuper(obj, args);
}
}
以 TestImpl 的调用耗时作为基准,对比通过其它三种代理进行调用的耗时。测试代码如下:
package com.hitd;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @Author ZhangWeinan
* @Date 2022/11/3 15:10
* @DES
* @Since Copyright(c)
*/
public class DynamicAndCglib {
public static void main(String[] args) {
//创建测试对象;
Test nativeTest = new TestImpl();
Test decorator = new StaticTest(nativeTest);
Test dynamicProxy = DynamicProxyTest.newProxyInstance(nativeTest);
Test cglibProxy = CglibProxyTest.newProxyInstance(TestImpl.class);
//预热一下;
int preRunCount = 10000;
runWithoutMonitor(nativeTest, preRunCount);
runWithoutMonitor(decorator, preRunCount);
runWithoutMonitor(cglibProxy, preRunCount);
runWithoutMonitor(dynamicProxy, preRunCount);
//执行测试;
Map<String, Test> tests = new LinkedHashMap<>();
tests.put("Native ", nativeTest);
tests.put("Static", decorator);
tests.put("Dynamic ", dynamicProxy);
tests.put("Cglib ", cglibProxy);
int repeatCount = 3;
int runCount = 1000000;
runTest(repeatCount, runCount, tests);
runCount = 50000000;
runTest(repeatCount, runCount, tests);
}
private static void runTest(int repeatCount, int runCount, Map<String, Test> tests){
System.out.println(String.format("\n==================== run test : [repeatCount=%s] [runCount=%s] [java.version=%s] ====================", repeatCount, runCount, System.getProperty("java.version")));
for (int i = 0; i < repeatCount; i++) {
System.out.println(String.format("\n--------- test : [%s] ---------", (i+1)));
for (String key : tests.keySet()) {
runWithMonitor(tests.get(key), runCount, key);
}
}
}
private static void runWithoutMonitor(Test test, int runCount) {
for (int i = 0; i < runCount; i++) {
test.test(i);
}
}
private static void runWithMonitor(Test test, int runCount, String tag) {
long start = System.currentTimeMillis();
for (int i = 0; i < runCount; i++) {
test.test(i);
}
long end = System.currentTimeMillis();
System.out.println("["+tag + "] Elapsed Time:" + (end-start) + "ms");
}
}
因为电脑只有jdk8 ,所以仅下其实进行了测试,每次测试分别以 1,000,000 和 50,000,000 循环次数调用 test 方法,并重复3次。
==================== run test : [repeatCount=3] [runCount=1000000] [java.version=1.8.0_321] ====================
--------- test : [1] ---------
[Native ] Elapsed Time:2ms
[Static] Elapsed Time:4ms
[Dynamic ] Elapsed Time:16ms
[Cglib ] Elapsed Time:20ms
--------- test : [2] ---------
[Native ] Elapsed Time:2ms
[Static] Elapsed Time:2ms
[Dynamic ] Elapsed Time:5ms
[Cglib ] Elapsed Time:10ms
--------- test : [3] ---------
[Native ] Elapsed Time:2ms
[Static] Elapsed Time:3ms
[Dynamic ] Elapsed Time:6ms
[Cglib ] Elapsed Time:11ms
==================== run test : [repeatCount=3] [runCount=50000000] [java.version=1.8.0_321] ====================
--------- test : [1] ---------
[Native ] Elapsed Time:142ms
[Static] Elapsed Time:134ms
[Dynamic ] Elapsed Time:337ms
[Cglib ] Elapsed Time:572ms
--------- test : [2] ---------
[Native ] Elapsed Time:117ms
[Static] Elapsed Time:128ms
[Dynamic ] Elapsed Time:250ms
[Cglib ] Elapsed Time:404ms
--------- test : [3] ---------
[Native ] Elapsed Time:121ms
[Static] Elapsed Time:121ms
[Dynamic ] Elapsed Time:256ms
[Cglib ] Elapsed Time:403ms
总结
其实在jdk1.6开始就已经没有所说的10倍的差距了,jdk1.7时jdk动态代理就已经超越了Cglib,到了jdk1.8时JDK动态代理已经比Cglib快了近40%,感兴趣的可去尝试1.6与1.7。从 jdk6 到 jdk7、jdk8 ,动态代理的性能得到了显著的提升,而 cglib 的表现并未跟上,所以Cglib比jdk动态代理快应该也只是存在于低版本中
评论区