Java 几种动态代理实现及其性能比较
原处出之于阿里liangf
Interface:
package com.sunchao.jdkdyproxy; public interface Subject { void request(); }
impl:
package com.sunchao.jdkdyproxy; public class RealSubject implements Subject { private int count; @Override public void request() { count++; //System.out.println("real subject does with the request!"); } }
jdk:
package com.sunchao.jdkdyproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ClientProxy { public static Subject createJdkDynamicProxy(final Object delegate) { return (Subject) Proxy.newProxyInstance(Thread.currentThread() .getContextClassLoader(), new Class<?>[] {Subject.class}, new MyInvocation(delegate)); } private static class MyInvocation implements InvocationHandler { final private Object delegate; MyInvocation(Object delegate) { this.delegate = delegate; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // System.out.println("aop before real request!"); return method.invoke(delegate, args); // System.out.println("aop after real request!"); //return null; } } public static void main(String args[]) { Subject delegate = new RealSubject(); Subject proxy = createJdkDynamicProxy(delegate); proxy.request(); } }
cglib:
package com.sunchao.cglibproxy; import java.lang.reflect.Method; import com.sunchao.jdkdyproxy.*; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxy { public static Subject createCglibDynamicProxy(final Object delegate) { Enhancer enhancer = new Enhancer(); enhancer.setCallback(new CglibInterceptor(delegate)); enhancer.setInterfaces(new Class<?>[]{Subject.class}); Subject cglibProxy = (Subject) enhancer.create(); return cglibProxy; } private static class CglibInterceptor implements MethodInterceptor { final private Object delegate; CglibInterceptor(Object delegate) { this.delegate =delegate; } @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { //System.out.println("aop before do with the request!"); return arg1.invoke(delegate, arg2); // System.out.println("aop before do with the request!"); //return null; } } public static void main(String args[]) { Subject realSubject = new RealSubject(); Subject cglibProxy = createCglibDynamicProxy(realSubject); cglibProxy.request(); } }
javasist dynamic proxy:
package com.sunchao.javasistproxy; import java.lang.reflect.Method; import com.sunchao.jdkdyproxy.Subject; import javassist.util.proxy.MethodHandler; import javassist.util.proxy.ProxyFactory; import javassist.util.proxy.ProxyObject; public class ClientProxy { public static Subject createJavasistDynamicProxy(final Subject delegate) throws Exception { ProxyFactory factory = new ProxyFactory(); factory.setInterfaces(new Class<?>[]{com.sunchao.jdkdyproxy.Subject.class}); Class<?> proxyClass = factory.createClass(); Subject javasistProxy = (Subject) proxyClass.newInstance(); ((ProxyObject)javasistProxy).setHandler(new JavasistInterceptor(delegate)); return javasistProxy; } private static class JavasistInterceptor implements MethodHandler { final private Object delegate; JavasistInterceptor(Object delegate) { this.delegate = delegate; } @Override public Object invoke(Object arg0, Method arg1, Method arg2, Object[] arg3) throws Throwable { //System.out.println("Aop before the real request"); return arg1.invoke(delegate, arg3); // System.out.println("Aop after the real request"); // return null; } } }
javasist bytecode proxy:
package com.sunchao.javasistproxy; import java.lang.reflect.Field; import javassist.ClassPool; import javassist.CtClass; import javassist.CtField; import javassist.CtNewConstructor; import javassist.CtNewMethod; import com.sunchao.jdkdyproxy.RealSubject; import com.sunchao.jdkdyproxy.Subject; public class ByteCodeProxy { public static Subject createJavasistBytecodeDynamicProxy(final Subject delegate) throws Exception { ClassPool pool = ClassPool.getDefault(); CtClass proxyClass = pool.makeClass(Subject.class.getName() + "JavasistProxy"); proxyClass.addInterface(pool.get(Subject.class.getName())); proxyClass.addConstructor(CtNewConstructor.defaultConstructor(proxyClass)); proxyClass.addField(CtField.make("private " + Subject.class.getName() + " delegate ;", proxyClass)); proxyClass.addMethod(CtNewMethod.make( "public void request() { delegate.request();}", proxyClass)); Class<?> clazz = proxyClass.toClass(); Subject bytecodeProxy = (Subject) clazz.newInstance(); Field field = bytecodeProxy.getClass().getDeclaredField("delegate"); field.setAccessible(true); field.set(bytecodeProxy,delegate); return bytecodeProxy; } public static void main(String args[]) throws Exception { Subject delegate = new RealSubject(); Subject bytecodeProxy = createJavasistBytecodeDynamicProxy(delegate); bytecodeProxy.request(); } }
asm:
package com.sunchao.asm; import java.lang.reflect.Field; import java.nio.ReadOnlyBufferException; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import com.sunchao.jdkdyproxy.RealSubject; import com.sunchao.jdkdyproxy.Subject; public class ASMProxy { public static Subject createAsmByteCodeDynamicProxy(Subject delegate) throws Exception { ClassWriter classWriter = new ClassWriter(true); String className = Subject.class.getName() + "AsmProxy"; String classPath = className.replace('.', '/'); String interfacePath = Subject.class.getName().replace('.', '/'); classWriter.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, classPath, null, "java/lang/Object", new String[] {interfacePath}); MethodVisitor initVistor = (MethodVisitor) classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); initVistor.visitCode(); initVistor.visitVarInsn(Opcodes.ALOAD, 0); initVistor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); initVistor.visitInsn(Opcodes.RETURN); initVistor.visitMaxs(0, 0); initVistor.visitEnd(); FieldVisitor fieldVisitor = classWriter.visitField(Opcodes.ACC_PRIVATE, "delegate" , "L" + interfacePath + ";" , null, null); fieldVisitor.visitEnd(); MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "request", "()V", null, null); methodVisitor.visitCode(); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitFieldInsn(Opcodes.GETFIELD, classPath, "delegate", "L" + interfacePath + ";"); methodVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, interfacePath, "request", "()V"); methodVisitor.visitInsn(Opcodes.RETURN); methodVisitor.visitMaxs(0, 0); methodVisitor.visitEnd(); classWriter.visitEnd(); byte[] code = classWriter.toByteArray(); Subject asmProxy = (Subject) new ByteArrayClassLoader().getClass(className, code).newInstance(); Field field = asmProxy.getClass().getDeclaredField("delegate"); field.setAccessible(true); field.set(asmProxy, delegate); return asmProxy; } private static class ByteArrayClassLoader extends ClassLoader { ByteArrayClassLoader() { super(ByteArrayClassLoader.getSystemClassLoader()); } public synchronized Class<?> getClass(String name, byte[] code) { if(name == null) throw new IllegalArgumentException("name == null"); return defineClass(name, code, 0, code.length); } } public static void main(String args[]) throws Exception{ Subject real = new RealSubject(); Subject asmProxy =createAsmByteCodeDynamicProxy(real); asmProxy.request(); } }
四种比较:
package com.sunchao.reflecttest; import java.text.DecimalFormat; import com.sunchao.asm.ASMProxy; import com.sunchao.cglibproxy.CglibProxy; import com.sunchao.javasistproxy.ByteCodeProxy; import com.sunchao.jdkdyproxy.ClientProxy; import com.sunchao.jdkdyproxy.RealSubject; import com.sunchao.jdkdyproxy.Subject; /** * * @author Administrator * */ public class DynamicProxyTest { public static void main(String args[]) throws Exception { Subject delegate = new RealSubject(); long time = System.currentTimeMillis(); Subject jdkProxy = ClientProxy.createJdkDynamicProxy(delegate); time = System.currentTimeMillis() - time; System.out.println("create jdk dynamic proxy : " + time + " ms"); time = System.currentTimeMillis(); Subject cglibProxy = CglibProxy.createCglibDynamicProxy(delegate); time = System.currentTimeMillis() - time; System.out.println("create cglib dynamic proxy : " + time + " ms"); time = System.currentTimeMillis(); Subject javasistProxy = com.sunchao.javasistproxy.ClientProxy.createJavasistDynamicProxy(delegate); time = System.currentTimeMillis() - time; System.out.println("create javasist dynamic proxy : " + time + " ms"); time = System.currentTimeMillis(); Subject javasistbytecodeProxy = ByteCodeProxy.createJavasistBytecodeDynamicProxy(delegate); time = System.currentTimeMillis() - time; System.out.println("create javasist bytecode proxy : " + time + " ms" ); time = System.currentTimeMillis(); Subject asmProxy = ASMProxy.createAsmByteCodeDynamicProxy(delegate); time = System.currentTimeMillis() - time; System.out.println("create asm bytecode proxy : " + time + " ms"); System.out.println("<============================================>"); for(int i = 0; i < 3; i++){ test(jdkProxy, "run the jdkDynamicProxy : "); test(cglibProxy, "run the cglibDynamicProxy : "); test(javasistProxy, "run the javasistProxy : "); test(javasistbytecodeProxy, "run the javasist byte code proxy : "); test(asmProxy, "run the asm byte code proxy : "); System.out.println("<-------------------------------------->"); } } public static void test(Subject delegate, String label) { delegate.request();//warm up int count = 10000000; long time = System.currentTimeMillis(); for(int i = 0; i < count; i++){ delegate.request(); } time = System.currentTimeMillis() - time; System.out.println(label + time + " ms, " + new DecimalFormat().format(count * 1000 / time) + " t/s"); } }
四种比较结果:
create jdk dynamic proxy : 9 ms
create cglib dynamic proxy : 169 ms
create javasist dynamic proxy : 109 ms
create javasist bytecode proxy : 375 ms
create asm bytecode proxy : 9 ms
<============================================>
run the jdkDynamicProxy : 864 ms, 1,632,020 t/s
run the cglibDynamicProxy : 794 ms, 1,775,901 t/s
run the javasistProxy : 816 ms, 1,728,021 t/s
run the javasist byte code proxy : 80 ms, 17,625,817 t/s
run the asm byte code proxy : 76 ms, 18,553,492 t/s
<-------------------------------------->
run the jdkDynamicProxy : 707 ms, 1,994,434 t/s
run the cglibDynamicProxy : 713 ms, 1,977,651 t/s
run the javasistProxy : 862 ms, 1,635,806 t/s
run the javasist byte code proxy : 66 ms, 21,364,627 t/s
run the asm byte code proxy : 73 ms, 19,315,964 t/s
<-------------------------------------->
run the jdkDynamicProxy : 740 ms, 1,905,493 t/s
run the cglibDynamicProxy : 693 ms, 2,034,726 t/s
run the javasistProxy : 844 ms, 1,670,693 t/s
run the javasist byte code proxy : 74 ms, 19,054,937 t/s
run the asm byte code proxy : 83 ms, 16,988,739 t/s
<-------------------------------------->
四种各种调用10000000次:
从创建动态代理类的时间可以看出:jdk和asm效果最优,javasist bytecode次之,在其次cglib,最差的是javasist dynamic proxy
从代理调用的时间可以看出:asm和javasist差不多最好,其他三个差不多,差距较大;
asm比较底层,对虚拟机指令要求高,综合javasist bytecode性能综合比较好,