JDK dynamic proxy and Cglib performance testing

Comparison of running performance between Cglib and JDK dynamic proxy

It is said that the running performance of the dynamic proxy created by Cglib is about 10 times higher than that of the JDK dynamic proxy. I verified that
the maven dependency was introduced.

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.3.20</version>
</dependency>

The code is very simple. First, define a Test interface and an implementation TestImpl. The Test interface only defines one method test, which adds 1 to the incoming int parameter and returns it. code show as below:

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;
    }
}

Then, three proxy implementations are defined: static proxy, JDK dynamic proxy and Cglib dynamic proxy. code show as below:

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);
    }

}

Use the calling time of TestImpl as a benchmark to compare the time-consuming of calling through the other three agents. The test code is as follows:

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");
    }
}


Because the computer only has jdk8, the test was actually carried out. Each test called the test method with 1,000,000 and 50,000,000 cycles respectively, and repeated it three times.
image-1667803532609

==================== 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

Summarize

In fact, there is no such 10 times gap since jdk1.6. In jdk1.7, jdk dynamic proxy has surpassed Cglib. By jdk1.8, JDK dynamic proxy is already nearly 40% faster than Cglib. Interested You can try 1.6 and 1.7. From jdk6 to jdk7 and jdk8, the performance of dynamic agents has been significantly improved, but the performance of cglib has not kept up, so Cglib is faster than jdk dynamic agents and should only exist in lower versions.

Guess you like

Origin blog.csdn.net/qq_49619863/article/details/127836335