- 浏览: 1700590 次
- 性别:
- 来自: 杭州699号
文章分类
最新评论
-
莫莫摸:
为什么不用dubbo
RCP数据传输模型回顾 -
大胡子爸爸:
String, Class 都实现了Serializable接 ...
RPC框架几行代码就够了 -
lss598018587:
谢谢大神分享,比起新手看复杂的dubbo框架还不如看大神的这一 ...
RPC框架几行代码就够了 -
15606915740:
你好,请问一下。<dubbo:consumer filt ...
Dubbo文档 -
joqk12345:
...
一些设计上的基本常识
转于自己在公司的Blog:
http://pt.alibaba-inc.com/wp/experience_1054/dynamic_proxy_performance.html
因服务框架需要用动态代理生成客户端接口的stub,所以做了一下性能评测,
动态代理工具比较成熟的产品有:
JDK自带的,ASM,CGLIB(基于ASM包装),JAVAASSIST,
使用的版本分别为:
JDK-1.6.0_18-b07, ASM-3.3, CGLIB-2.2, JAVAASSIST-3.11.0.GA
(一) 测试结果:
数据为执行三次,每次调用一千万次代理方法的结果,测试代码后面有贴出。
(1) PC机测试结果:Linux 2.6.9-42.ELsmp(32bit), 2 Cores CPU(Intel Pentium4 3.06GHz)
(2) 服务器测试结果:Linux 2.6.18-128.el5xen(64bit), 16 Cores CPU(Intel Xeon E5520 2.27GHz)
(二) 测试结论:
1. ASM和JAVAASSIST字节码生成方式不相上下,都很快,是CGLIB的5倍。
2. CGLIB次之,是JDK自带的两倍。
3. JDK自带的再次之,因JDK1.6对动态代理做了优化,如果用低版本JDK更慢,要注意的是JDK也是通过字节码生成来实现动态代理的,而不是反射。
4. JAVAASSIST提供者动态代理接口最慢,比JDK自带的还慢。
(这也是为什么网上有人说JAVAASSIST比JDK还慢的原因,用JAVAASSIST最好别用它提供的动态代理接口,而可以考虑用它的字节码生成方式)
(三) 差异原因:
各方案生成的字节码不一样,
像JDK和CGLIB都考虑了很多因素,以及继承或包装了自己的一些类,
所以生成的字节码非常大,而我们很多时候用不上这些,
而手工生成的字节码非常小,所以速度快,
具体的字节码对比,后面有贴出,可自行分析。
(四) 最终选型:
最终决定使用JAVAASSIST的字节码生成代理方式,
虽然ASM稍快,但并没有快一个数量级,
而JAVAASSIST的字节码生成方式比ASM方便,
JAVAASSIST只需用字符串拼接出Java源码,便可生成相应字节码,
而ASM需要手工写字节码。
(五) 测试代码:
(六) 字节码对比
(1) JDK生成的字节码:
(2) CGLIB生成的字节码:
(3) JAVAASSIST动态代理接口生成的字节码:
(5) JAVAASSIST拼接源码生成的字节码:
(6) 用ASM自行生成的字节码:
Gavin King也是RedHat旗下的,当然选同宗的了,呵呵。
可以用:
javap -c 类名
http://pt.alibaba-inc.com/wp/experience_1054/dynamic_proxy_performance.html
因服务框架需要用动态代理生成客户端接口的stub,所以做了一下性能评测,
动态代理工具比较成熟的产品有:
JDK自带的,ASM,CGLIB(基于ASM包装),JAVAASSIST,
使用的版本分别为:
JDK-1.6.0_18-b07, ASM-3.3, CGLIB-2.2, JAVAASSIST-3.11.0.GA
(一) 测试结果:
数据为执行三次,每次调用一千万次代理方法的结果,测试代码后面有贴出。
(1) PC机测试结果:Linux 2.6.9-42.ELsmp(32bit), 2 Cores CPU(Intel Pentium4 3.06GHz)
Create JDK Proxy: 13 ms Create CGLIB Proxy: 217 ms Create JAVAASSIST Proxy: 99 ms Create JAVAASSIST Bytecode Proxy: 168 ms Create ASM Proxy: 3 ms ================ Run JDK Proxy: 2224 ms, 634,022 t/s Run CGLIB Proxy: 1123 ms, 1,255,623 t/s Run JAVAASSIST Proxy: 3212 ms, 438,999 t/s Run JAVAASSIST Bytecode Proxy: 206 ms, 6,844,977 t/s Run ASM Bytecode Proxy: 209 ms, 6,746,724 t/s ---------------- Run JDK Proxy: 2169 ms, 650,099 t/s Run CGLIB Proxy: 1059 ms, 1,331,506 t/s Run JAVAASSIST Proxy: 3328 ms, 423,697 t/s Run JAVAASSIST Bytecode Proxy: 202 ms, 6,980,521 t/s Run ASM Bytecode Proxy: 206 ms, 6,844,977 t/s ---------------- Run JDK Proxy: 2174 ms, 648,604 t/s Run CGLIB Proxy: 1032 ms, 1,366,342 t/s Run JAVAASSIST Proxy: 3119 ms, 452,088 t/s Run JAVAASSIST Bytecode Proxy: 207 ms, 6,811,910 t/s Run ASM Bytecode Proxy: 207 ms, 6,811,910 t/s ----------------
(2) 服务器测试结果:Linux 2.6.18-128.el5xen(64bit), 16 Cores CPU(Intel Xeon E5520 2.27GHz)
Create JDK Proxy: 7 ms Create CGLIB Proxy: 86 ms Create JAVAASSIST Proxy: 36 ms Create JAVAASSIST Bytecode Proxy: 57 ms Create ASM Proxy: 1 ms ================ Run JDK Proxy: 235 ms, 6,000,278 t/s Run CGLIB Proxy: 234 ms, 6,025,920 t/s Run JAVAASSIST Proxy: 459 ms, 3,072,037 t/s Run JAVAASSIST Bytecode Proxy: 71 ms, 19,860,076 t/s Run ASM Bytecode Proxy: 72 ms, 19,584,241 t/s ---------------- Run JDK Proxy: 298 ms, 4,731,763 t/s Run CGLIB Proxy: 134 ms, 10,522,876 t/s Run JAVAASSIST Proxy: 406 ms, 3,473,067 t/s Run JAVAASSIST Bytecode Proxy: 67 ms, 21,045,752 t/s Run ASM Bytecode Proxy: 66 ms, 21,364,627 t/s ---------------- Run JDK Proxy: 282 ms, 5,000,231 t/s Run CGLIB Proxy: 133 ms, 10,601,995 t/s Run JAVAASSIST Proxy: 406 ms, 3,473,067 t/s Run JAVAASSIST Bytecode Proxy: 67 ms, 21,045,752 t/s Run ASM Bytecode Proxy: 67 ms, 21,045,752 t/s ----------------
(二) 测试结论:
1. ASM和JAVAASSIST字节码生成方式不相上下,都很快,是CGLIB的5倍。
2. CGLIB次之,是JDK自带的两倍。
3. JDK自带的再次之,因JDK1.6对动态代理做了优化,如果用低版本JDK更慢,要注意的是JDK也是通过字节码生成来实现动态代理的,而不是反射。
4. JAVAASSIST提供者动态代理接口最慢,比JDK自带的还慢。
(这也是为什么网上有人说JAVAASSIST比JDK还慢的原因,用JAVAASSIST最好别用它提供的动态代理接口,而可以考虑用它的字节码生成方式)
(三) 差异原因:
各方案生成的字节码不一样,
像JDK和CGLIB都考虑了很多因素,以及继承或包装了自己的一些类,
所以生成的字节码非常大,而我们很多时候用不上这些,
而手工生成的字节码非常小,所以速度快,
具体的字节码对比,后面有贴出,可自行分析。
(四) 最终选型:
最终决定使用JAVAASSIST的字节码生成代理方式,
虽然ASM稍快,但并没有快一个数量级,
而JAVAASSIST的字节码生成方式比ASM方便,
JAVAASSIST只需用字符串拼接出Java源码,便可生成相应字节码,
而ASM需要手工写字节码。
(五) 测试代码:
public interface CountService { int count(); }
public class CountServiceImpl implements CountService { private int count = 0; public int count() { return count ++; } }
import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.text.DecimalFormat; import javassist.ClassPool; import javassist.CtClass; import javassist.CtField; import javassist.CtNewConstructor; import javassist.CtNewMethod; import javassist.util.proxy.MethodHandler; import javassist.util.proxy.ProxyFactory; import javassist.util.proxy.ProxyObject; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; public class DynamicProxyPerformanceTest { public static void main(String[] args) throws Exception { CountService delegate = new CountServiceImpl(); long time = System.currentTimeMillis(); CountService jdkProxy = createJdkDynamicProxy(delegate); time = System.currentTimeMillis() - time; System.out.println("Create JDK Proxy: " + time + " ms"); time = System.currentTimeMillis(); CountService cglibProxy = createCglibDynamicProxy(delegate); time = System.currentTimeMillis() - time; System.out.println("Create CGLIB Proxy: " + time + " ms"); time = System.currentTimeMillis(); CountService javassistProxy = createJavassistDynamicProxy(delegate); time = System.currentTimeMillis() - time; System.out.println("Create JAVAASSIST Proxy: " + time + " ms"); time = System.currentTimeMillis(); CountService javassistBytecodeProxy = createJavassistBytecodeDynamicProxy(delegate); time = System.currentTimeMillis() - time; System.out.println("Create JAVAASSIST Bytecode Proxy: " + time + " ms"); time = System.currentTimeMillis(); CountService asmBytecodeProxy = createAsmBytecodeDynamicProxy(delegate); time = System.currentTimeMillis() - time; System.out.println("Create ASM Proxy: " + time + " ms"); System.out.println("================"); for (int i = 0; i < 3; i++) { test(jdkProxy, "Run JDK Proxy: "); test(cglibProxy, "Run CGLIB Proxy: "); test(javassistProxy, "Run JAVAASSIST Proxy: "); test(javassistBytecodeProxy, "Run JAVAASSIST Bytecode Proxy: "); test(asmBytecodeProxy, "Run ASM Bytecode Proxy: "); System.out.println("----------------"); } } private static void test(CountService service, String label) throws Exception { service.count(); // warm up int count = 10000000; long time = System.currentTimeMillis(); for (int i = 0; i < count; i++) { service.count(); } time = System.currentTimeMillis() - time; System.out.println(label + time + " ms, " + new DecimalFormat().format(count * 1000 / time) + " t/s"); } private static CountService createJdkDynamicProxy(final CountService delegate) { CountService jdkProxy = (CountService) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] { CountService.class }, new JdkHandler(delegate)); return jdkProxy; } private static class JdkHandler implements InvocationHandler { final Object delegate; JdkHandler(Object delegate) { this.delegate = delegate; } public Object invoke(Object object, Method method, Object[] objects) throws Throwable { return method.invoke(delegate, objects); } } private static CountService createCglibDynamicProxy(final CountService delegate) throws Exception { Enhancer enhancer = new Enhancer(); enhancer.setCallback(new CglibInterceptor(delegate)); enhancer.setInterfaces(new Class[] { CountService.class }); CountService cglibProxy = (CountService) enhancer.create(); return cglibProxy; } private static class CglibInterceptor implements MethodInterceptor { final Object delegate; CglibInterceptor(Object delegate) { this.delegate = delegate; } public Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { return methodProxy.invoke(delegate, objects); } } private static CountService createJavassistDynamicProxy(final CountService delegate) throws Exception { ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setInterfaces(new Class[] { CountService.class }); Class<?> proxyClass = proxyFactory.createClass(); CountService javassistProxy = (CountService) proxyClass.newInstance(); ((ProxyObject) javassistProxy).setHandler(new JavaAssitInterceptor(delegate)); return javassistProxy; } private static class JavaAssitInterceptor implements MethodHandler { final Object delegate; JavaAssitInterceptor(Object delegate) { this.delegate = delegate; } public Object invoke(Object self, Method m, Method proceed, Object[] args) throws Throwable { return m.invoke(delegate, args); } } private static CountService createJavassistBytecodeDynamicProxy(CountService delegate) throws Exception { ClassPool mPool = new ClassPool(true); CtClass mCtc = mPool.makeClass(CountService.class.getName() + "JavaassistProxy"); mCtc.addInterface(mPool.get(CountService.class.getName())); mCtc.addConstructor(CtNewConstructor.defaultConstructor(mCtc)); mCtc.addField(CtField.make("public " + CountService.class.getName() + " delegate;", mCtc)); mCtc.addMethod(CtNewMethod.make("public int count() { return delegate.count(); }", mCtc)); Class<?> pc = mCtc.toClass(); CountService bytecodeProxy = (CountService) pc.newInstance(); Field filed = bytecodeProxy.getClass().getField("delegate"); filed.set(bytecodeProxy, delegate); return bytecodeProxy; } private static CountService createAsmBytecodeDynamicProxy(CountService delegate) throws Exception { ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); String className = CountService.class.getName() + "AsmProxy"; String classPath = className.replace('.', '/'); String interfacePath = CountService.class.getName().replace('.', '/'); classWriter.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, classPath, null, "java/lang/Object", new String[] {interfacePath}); MethodVisitor initVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); initVisitor.visitCode(); initVisitor.visitVarInsn(Opcodes.ALOAD, 0); initVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); initVisitor.visitInsn(Opcodes.RETURN); initVisitor.visitMaxs(0, 0); initVisitor.visitEnd(); FieldVisitor fieldVisitor = classWriter.visitField(Opcodes.ACC_PUBLIC, "delegate", "L" + interfacePath + ";", null, null); fieldVisitor.visitEnd(); MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "count", "()I", null, null); methodVisitor.visitCode(); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitFieldInsn(Opcodes.GETFIELD, classPath, "delegate", "L" + interfacePath + ";"); methodVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, interfacePath, "count", "()I"); methodVisitor.visitInsn(Opcodes.IRETURN); methodVisitor.visitMaxs(0, 0); methodVisitor.visitEnd(); classWriter.visitEnd(); byte[] code = classWriter.toByteArray(); CountService bytecodeProxy = (CountService) new ByteArrayClassLoader().getClass(className, code).newInstance(); Field filed = bytecodeProxy.getClass().getField("delegate"); filed.set(bytecodeProxy, delegate); return bytecodeProxy; } private static class ByteArrayClassLoader extends ClassLoader { public ByteArrayClassLoader() { super(ByteArrayClassLoader.class.getClassLoader()); } public synchronized Class<?> getClass(String name, byte[] code) { if (name == null) { throw new IllegalArgumentException(""); } return defineClass(name, code, 0, code.length); } } }
(六) 字节码对比
(1) JDK生成的字节码:
public final class $Proxy0 extends java.lang.reflect.Proxy implements com.alibaba.test.performance.dynamicproxy.CountService{ public $Proxy0(java.lang.reflect.InvocationHandler) throws ; Code: 0: aload_0 1: aload_1 2: invokespecial #8; //Method java/lang/reflect/Proxy."":(Ljava/lang/reflect/InvocationHandler;)V 5: return public final boolean equals(java.lang.Object) throws ; Code: 0: aload_0 1: getfield #16; //Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler; 4: aload_0 5: getstatic #20; //Field m1:Ljava/lang/reflect/Method; 8: iconst_1 9: anewarray #22; //class java/lang/Object 12: dup 13: iconst_0 14: aload_1 15: aastore 16: invokeinterface #28, 4; //InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; 21: checkcast #30; //class java/lang/Boolean 24: invokevirtual #34; //Method java/lang/Boolean.booleanValue:()Z 27: ireturn 28: athrow 29: astore_2 30: new #42; //class java/lang/reflect/UndeclaredThrowableException 33: dup 34: aload_2 35: invokespecial #45; //Method java/lang/reflect/UndeclaredThrowableException."":(Ljava/lang/Throwable;)V 38: athrow Exception table: from to target type 0 28 28 Class java/lang/Error 0 28 28 Class java/lang/RuntimeException 0 28 29 Class java/lang/Throwable public final int count() throws ; Code: 0: aload_0 1: getfield #16; //Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler; 4: aload_0 5: getstatic #50; //Field m3:Ljava/lang/reflect/Method; 8: aconst_null 9: invokeinterface #28, 4; //InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; 14: checkcast #52; //class java/lang/Integer 17: invokevirtual #55; //Method java/lang/Integer.intValue:()I 20: ireturn 21: athrow 22: astore_1 23: new #42; //class java/lang/reflect/UndeclaredThrowableException 26: dup 27: aload_1 28: invokespecial #45; //Method java/lang/reflect/UndeclaredThrowableException."":(Ljava/lang/Throwable;)V 31: athrow Exception table: from to target type 0 21 21 Class java/lang/Error 0 21 21 Class java/lang/RuntimeException 0 21 22 Class java/lang/Throwable public final int hashCode() throws ; Code: 0: aload_0 1: getfield #16; //Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler; 4: aload_0 5: getstatic #59; //Field m0:Ljava/lang/reflect/Method; 8: aconst_null 9: invokeinterface #28, 4; //InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; 14: checkcast #52; //class java/lang/Integer 17: invokevirtual #55; //Method java/lang/Integer.intValue:()I 20: ireturn 21: athrow 22: astore_1 23: new #42; //class java/lang/reflect/UndeclaredThrowableException 26: dup 27: aload_1 28: invokespecial #45; //Method java/lang/reflect/UndeclaredThrowableException."":(Ljava/lang/Throwable;)V 31: athrow Exception table: from to target type 0 21 21 Class java/lang/Error 0 21 21 Class java/lang/RuntimeException 0 21 22 Class java/lang/Throwable public final java.lang.String toString() throws ; Code: 0: aload_0 1: getfield #16; //Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler; 4: aload_0 5: getstatic #64; //Field m2:Ljava/lang/reflect/Method; 8: aconst_null 9: invokeinterface #28, 4; //InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; 14: checkcast #66; //class java/lang/String 17: areturn 18: athrow 19: astore_1 20: new #42; //class java/lang/reflect/UndeclaredThrowableException 23: dup 24: aload_1 25: invokespecial #45; //Method java/lang/reflect/UndeclaredThrowableException."":(Ljava/lang/Throwable;)V 28: athrow Exception table: from to target type 0 18 18 Class java/lang/Error 0 18 18 Class java/lang/RuntimeException 0 18 19 Class java/lang/Throwable static {} throws ; Code: 0: ldc #70; //String java.lang.Object 2: invokestatic #76; //Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class; 5: ldc #77; //String equals 7: iconst_1 8: anewarray #72; //class java/lang/Class 11: dup 12: iconst_0 13: ldc #70; //String java.lang.Object 15: invokestatic #76; //Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class; 18: aastore 19: invokevirtual #81; //Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method; 22: putstatic #20; //Field m1:Ljava/lang/reflect/Method; 25: ldc #83; //String com.alibaba.test.performance.dynamicproxy.CountService 27: invokestatic #76; //Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class; 30: ldc #84; //String count 32: iconst_0 33: anewarray #72; //class java/lang/Class 36: invokevirtual #81; //Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method; 39: putstatic #50; //Field m3:Ljava/lang/reflect/Method; 42: ldc #70; //String java.lang.Object 44: invokestatic #76; //Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class; 47: ldc #85; //String hashCode 49: iconst_0 50: anewarray #72; //class java/lang/Class 53: invokevirtual #81; //Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method; 56: putstatic #59; //Field m0:Ljava/lang/reflect/Method; 59: ldc #70; //String java.lang.Object 61: invokestatic #76; //Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class; 64: ldc #86; //String toString 66: iconst_0 67: anewarray #72; //class java/lang/Class 70: invokevirtual #81; //Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method; 73: putstatic #64; //Field m2:Ljava/lang/reflect/Method; 76: return 77: astore_1 78: new #90; //class java/lang/NoSuchMethodError 81: dup 82: aload_1 83: invokevirtual #93; //Method java/lang/Throwable.getMessage:()Ljava/lang/String; 86: invokespecial #96; //Method java/lang/NoSuchMethodError."":(Ljava/lang/String;)V 89: athrow 90: astore_1 91: new #100; //class java/lang/NoClassDefFoundError 94: dup 95: aload_1 96: invokevirtual #93; //Method java/lang/Throwable.getMessage:()Ljava/lang/String; 99: invokespecial #101; //Method java/lang/NoClassDefFoundError."":(Ljava/lang/String;)V 102: athrow Exception table: from to target type 0 77 77 Class java/lang/NoSuchMethodException 0 77 90 Class java/lang/ClassNotFoundException }
(2) CGLIB生成的字节码:
public class net.sf.cglib.core.MethodWrapper$MethodWrapperKey$$KeyFactoryByCGLIB$$d45e49f7 extends net.sf.cglib.core.KeyFactory implements net.sf.cglib.core.MethodWrapper$MethodWrapperKey{ public net.sf.cglib.core.MethodWrapper$MethodWrapperKey$$KeyFactoryByCGLIB$$d45e49f7(); Code: 0: aload_0 1: invokespecial #11; //Method net/sf/cglib/core/KeyFactory."":()V 4: return public java.lang.Object newInstance(java.lang.String, java.lang.String[], java.lang.String); Code: 0: new #2; //class net/sf/cglib/core/MethodWrapper$MethodWrapperKey$$KeyFactoryByCGLIB$$d45e49f7 3: dup 4: aload_1 5: aload_2 6: aload_3 7: invokespecial #16; //Method "":(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V 10: areturn public net.sf.cglib.core.MethodWrapper$MethodWrapperKey$$KeyFactoryByCGLIB$$d45e49f7(java.lang.String, java.lang.String[], java.lang.String); Code: 0: aload_0 1: invokespecial #11; //Method net/sf/cglib/core/KeyFactory."":()V 4: aload_0 5: dup 6: aload_1 7: putfield #20; //Field FIELD_0:Ljava/lang/String; 10: dup 11: aload_2 12: putfield #24; //Field FIELD_1:[Ljava/lang/String; 15: dup 16: aload_3 17: putfield #27; //Field FIELD_2:Ljava/lang/String; 20: return public int hashCode(); Code: 0: ldc #30; //int 938313161 2: aload_0 3: getfield #20; //Field FIELD_0:Ljava/lang/String; 6: swap 7: ldc #31; //int 362693231 9: imul 10: swap 11: dup 12: ifnull 21 15: invokevirtual #35; //Method java/lang/Object.hashCode:()I 18: goto 23 21: pop 22: iconst_0 23: iadd 24: aload_0 25: getfield #24; //Field FIELD_1:[Ljava/lang/String; 28: dup 29: ifnull 71 32: astore_1 33: iconst_0 34: istore_2 35: goto 62 38: aload_1 39: iload_2 40: aaload 41: swap 42: ldc #31; //int 362693231 44: imul 45: swap 46: dup 47: ifnull 56 50: invokevirtual #35; //Method java/lang/Object.hashCode:()I 53: goto 58 56: pop 57: iconst_0 58: iadd 59: iinc 2, 1 62: iload_2 63: aload_1 64: arraylength 65: if_icmplt 38 68: goto 72 71: pop 72: aload_0 73: getfield #27; //Field FIELD_2:Ljava/lang/String; 76: swap 77: ldc #31; //int 362693231 79: imul 80: swap 81: dup 82: ifnull 91 85: invokevirtual #35; //Method java/lang/Object.hashCode:()I 88: goto 93 91: pop 92: iconst_0 93: iadd 94: ireturn public boolean equals(java.lang.Object); Code: 0: aload_1 1: instanceof #2; //class net/sf/cglib/core/MethodWrapper$MethodWrapperKey$$KeyFactoryByCGLIB$$d45e49f7 4: ifeq 181 7: aload_0 8: getfield #20; //Field FIELD_0:Ljava/lang/String; 11: aload_1 12: checkcast #2; //class net/sf/cglib/core/MethodWrapper$MethodWrapperKey$$KeyFactoryByCGLIB$$d45e49f7 15: getfield #20; //Field FIELD_0:Ljava/lang/String; 18: dup2 19: ifnonnull 29 22: ifnonnull 35 25: pop2 26: goto 45 29: ifnull 35 32: goto 39 35: pop2 36: goto 181 39: invokevirtual #39; //Method java/lang/Object.equals:(Ljava/lang/Object;)Z 42: ifeq 181 45: aload_0 46: getfield #24; //Field FIELD_1:[Ljava/lang/String; 49: aload_1 50: checkcast #2; //class net/sf/cglib/core/MethodWrapper$MethodWrapperKey$$KeyFactoryByCGLIB$$d45e49f7 53: getfield #24; //Field FIELD_1:[Ljava/lang/String; 56: dup2 57: ifnonnull 67 60: ifnonnull 73 63: pop2 64: goto 141 67: ifnull 73 70: goto 77 73: pop2 74: goto 181 77: dup2 78: arraylength 79: swap 80: arraylength 81: if_icmpeq 88 84: pop2 85: goto 181 88: astore_2 89: astore_3 90: iconst_0 91: istore 4 93: goto 134 96: aload_2 97: iload 4 99: aaload 100: aload_3 101: iload 4 103: aaload 104: dup2 105: ifnonnull 115 108: ifnonnull 121 111: pop2 112: goto 131 115: ifnull 121 118: goto 125 121: pop2 122: goto 181 125: invokevirtual #39; //Method java/lang/Object.equals:(Ljava/lang/Object;)Z 128: ifeq 181 131: iinc 4, 1 134: iload 4 136: aload_2 137: arraylength 138: if_icmplt 96 141: aload_0 142: getfield #27; //Field FIELD_2:Ljava/lang/String; 145: aload_1 146: checkcast #2; //class net/sf/cglib/core/MethodWrapper$MethodWrapperKey$$KeyFactoryByCGLIB$$d45e49f7 149: getfield #27; //Field FIELD_2:Ljava/lang/String; 152: dup2 153: ifnonnull 163 156: ifnonnull 169 159: pop2 160: goto 179 163: ifnull 169 166: goto 173 169: pop2 170: goto 181 173: invokevirtual #39; //Method java/lang/Object.equals:(Ljava/lang/Object;)Z 176: ifeq 181 179: iconst_1 180: ireturn 181: iconst_0 182: ireturn public java.lang.String toString(); Code: 0: new #43; //class java/lang/StringBuffer 3: dup 4: invokespecial #44; //Method java/lang/StringBuffer."":()V 7: aload_0 8: getfield #20; //Field FIELD_0:Ljava/lang/String; 11: dup 12: ifnull 24 15: invokevirtual #46; //Method java/lang/Object.toString:()Ljava/lang/String; 18: invokevirtual #50; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 21: goto 30 24: pop 25: ldc #52; //String null 27: invokevirtual #50; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 30: ldc #54; //String , 32: invokevirtual #50; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 35: aload_0 36: getfield #24; //Field FIELD_1:[Ljava/lang/String; 39: dup 40: ifnull 110 43: swap 44: ldc #56; //String { 46: invokevirtual #50; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 49: swap 50: astore_1 51: iconst_0 52: istore_2 53: goto 86 56: aload_1 57: iload_2 58: aaload 59: dup 60: ifnull 72 63: invokevirtual #46; //Method java/lang/Object.toString:()Ljava/lang/String; 66: invokevirtual #50; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 69: goto 78 72: pop 73: ldc #52; //String null 75: invokevirtual #50; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 78: ldc #54; //String , 80: invokevirtual #50; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 83: iinc 2, 1 86: iload_2 87: aload_1 88: arraylength 89: if_icmplt 56 92: dup 93: dup 94: invokevirtual #59; //Method java/lang/StringBuffer.length:()I 97: iconst_2 98: isub 99: invokevirtual #63; //Method java/lang/StringBuffer.setLength:(I)V 102: ldc #65; //String } 104: invokevirtual #50; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 107: goto 116 110: pop 111: ldc #52; //String null 113: invokevirtual #50; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 116: ldc #54; //String , 118: invokevirtual #50; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 121: aload_0 122: getfield #27; //Field FIELD_2:Ljava/lang/String; 125: dup 126: ifnull 138 129: invokevirtual #46; //Method java/lang/Object.toString:()Ljava/lang/String; 132: invokevirtual #50; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 135: goto 144 138: pop 139: ldc #52; //String null 141: invokevirtual #50; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 144: invokevirtual #66; //Method java/lang/StringBuffer.toString:()Ljava/lang/String; 147: areturn }
(3) JAVAASSIST动态代理接口生成的字节码:
public class com.alibaba.test.performance.dynamicproxy.CountService_$$_javassist_0 extends java.lang.Object implements com.alibaba.test.performance.dynamicproxy.CountService,javassist.util.proxy.ProxyObject{ public static javassist.util.proxy.MethodHandler default_interceptor; public static javassist.util.proxy.MethodFilter _method_filter; public com.alibaba.test.performance.dynamicproxy.CountService_$$_javassist_0(); Code: 0: aload_0 1: getstatic #19; //Field default_interceptor:Ljavassist/util/proxy/MethodHandler; 4: putfield #21; //Field handler:Ljavassist/util/proxy/MethodHandler; 7: getstatic #23; //Field default_interceptor:Ljavassist/util/proxy/MethodHandler; 10: ifnonnull 20 13: aload_0 14: getstatic #27; //Field javassist/util/proxy/RuntimeSupport.default_interceptor:Ljavassist/util/proxy/MethodHandler; 17: putfield #29; //Field handler:Ljavassist/util/proxy/MethodHandler; 20: aload_0 21: invokespecial #31; //Method java/lang/Object."":()V 24: return public final boolean _d0equals(java.lang.Object); Code: 0: aload_0 1: aload_1 2: invokespecial #38; //Method java/lang/Object.equals:(Ljava/lang/Object;)Z 5: ireturn public final boolean equals(java.lang.Object); Code: 0: getstatic #42; //Field _methods_:[Ljava/lang/reflect/Method; 3: astore_2 4: aload_0 5: ldc #43; //String equals 7: ldc #44; //String _d0equals 9: iconst_0 10: ldc #45; //String (Ljava/lang/Object;)Z 12: aload_2 13: invokestatic #49; //Method javassist/util/proxy/RuntimeSupport.find2Methods:(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V 16: aload_0 17: getfield #51; //Field handler:Ljavassist/util/proxy/MethodHandler; 20: aload_0 21: aload_2 22: iconst_0 23: aaload 24: aload_2 25: iconst_1 26: aaload 27: iconst_1 28: anewarray #52; //class java/lang/Object 31: dup 32: iconst_0 33: aload_1 34: aastore 35: invokeinterface #58, 5; //InterfaceMethod javassist/util/proxy/MethodHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; 40: checkcast #60; //class java/lang/Boolean 43: invokevirtual #64; //Method java/lang/Boolean.booleanValue:()Z 46: ireturn public final java.lang.Object _d1clone() throws java.lang.CloneNotSupportedException; Code: 0: aload_0 1: invokespecial #72; //Method java/lang/Object.clone:()Ljava/lang/Object; 4: areturn protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException; Code: 0: getstatic #74; //Field _methods_:[Ljava/lang/reflect/Method; 3: astore_1 4: aload_0 5: ldc #75; //String clone 7: ldc #76; //String _d1clone 9: iconst_2 10: ldc #77; //String ()Ljava/lang/Object; 12: aload_1 13: invokestatic #79; //Method javassist/util/proxy/RuntimeSupport.find2Methods:(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V 16: aload_0 17: getfield #81; //Field handler:Ljavassist/util/proxy/MethodHandler; 20: aload_0 21: aload_1 22: iconst_2 23: aaload 24: aload_1 25: iconst_3 26: aaload 27: iconst_0 28: anewarray #52; //class java/lang/Object 31: invokeinterface #83, 5; //InterfaceMethod javassist/util/proxy/MethodHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; 36: checkcast #4; //class java/lang/Object 39: areturn public final int _d2hashCode(); Code: 0: aload_0 1: invokespecial #88; //Method java/lang/Object.hashCode:()I 4: ireturn public final int hashCode(); Code: 0: getstatic #90; //Field _methods_:[Ljava/lang/reflect/Method; 3: astore_1 4: aload_0 5: ldc #91; //String hashCode 7: ldc #92; //String _d2hashCode 9: iconst_4 10: ldc #93; //String ()I 12: aload_1 13: invokestatic #95; //Method javassist/util/proxy/RuntimeSupport.find2Methods:(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V 16: aload_0 17: getfield #97; //Field handler:Ljavassist/util/proxy/MethodHandler; 20: aload_0 21: aload_1 22: iconst_4 23: aaload 24: aload_1 25: iconst_5 26: aaload 27: iconst_0 28: anewarray #52; //class java/lang/Object 31: invokeinterface #99, 5; //InterfaceMethod javassist/util/proxy/MethodHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; 36: checkcast #101; //class java/lang/Integer 39: invokevirtual #104; //Method java/lang/Integer.intValue:()I 42: ireturn public final int count(); Code: 0: getstatic #107; //Field _methods_:[Ljava/lang/reflect/Method; 3: astore_1 4: aload_0 5: ldc #108; //String count 7: aconst_null 8: bipush 6 10: ldc #109; //String ()I 12: aload_1 13: invokestatic #111; //Method javassist/util/proxy/RuntimeSupport.find2Methods:(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V 16: aload_0 17: getfield #113; //Field handler:Ljavassist/util/proxy/MethodHandler; 20: aload_0 21: aload_1 22: bipush 6 24: aaload 25: aload_1 26: bipush 7 28: aaload 29: iconst_0 30: anewarray #52; //class java/lang/Object 33: invokeinterface #115, 5; //InterfaceMethod javassist/util/proxy/MethodHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; 38: checkcast #101; //class java/lang/Integer 41: invokevirtual #117; //Method java/lang/Integer.intValue:()I 44: ireturn public final void _d4finalize() throws java.lang.Throwable; Code: 0: aload_0 1: invokespecial #123; //Method java/lang/Object.finalize:()V 4: return protected final void finalize() throws java.lang.Throwable; Code: 0: getstatic #125; //Field _methods_:[Ljava/lang/reflect/Method; 3: astore_1 4: aload_0 5: ldc #126; //String finalize 7: ldc #127; //String _d4finalize 9: bipush 8 11: ldc #128; //String ()V 13: aload_1 14: invokestatic #130; //Method javassist/util/proxy/RuntimeSupport.find2Methods:(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V 17: aload_0 18: getfield #132; //Field handler:Ljavassist/util/proxy/MethodHandler; 21: aload_0 22: aload_1 23: bipush 8 25: aaload 26: aload_1 27: bipush 9 29: aaload 30: iconst_0 31: anewarray #52; //class java/lang/Object 34: invokeinterface #134, 5; //InterfaceMethod javassist/util/proxy/MethodHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; 39: pop 40: return public final java.lang.String _d5toString(); Code: 0: aload_0 1: invokespecial #139; //Method java/lang/Object.toString:()Ljava/lang/String; 4: areturn public final java.lang.String toString(); Code: 0: getstatic #141; //Field _methods_:[Ljava/lang/reflect/Method; 3: astore_1 4: aload_0 5: ldc #142; //String toString 7: ldc #143; //String _d5toString 9: bipush 10 11: ldc #144; //String ()Ljava/lang/String; 13: aload_1 14: invokestatic #146; //Method javassist/util/proxy/RuntimeSupport.find2Methods:(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V 17: aload_0 18: getfield #148; //Field handler:Ljavassist/util/proxy/MethodHandler; 21: aload_0 22: aload_1 23: bipush 10 25: aaload 26: aload_1 27: bipush 11 29: aaload 30: iconst_0 31: anewarray #52; //class java/lang/Object 34: invokeinterface #150, 5; //InterfaceMethod javassist/util/proxy/MethodHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; 39: checkcast #152; //class java/lang/String 42: areturn static {}; Code: 0: bipush 12 2: anewarray #155; //class java/lang/reflect/Method 5: putstatic #157; //Field _methods_:[Ljava/lang/reflect/Method; 8: return public void setHandler(javassist.util.proxy.MethodHandler); Code: 0: aload_0 1: aload_1 2: putfield #161; //Field handler:Ljavassist/util/proxy/MethodHandler; 5: return java.lang.Object writeReplace() throws java.io.ObjectStreamException; Code: 0: aload_0 1: invokestatic #168; //Method javassist/util/proxy/RuntimeSupport.makeSerializedProxy:(Ljava/lang/Object;)Ljavassist/util/proxy/SerializedProxy; 4: areturn }
(5) JAVAASSIST拼接源码生成的字节码:
public class com.alibaba.test.performance.dynamicproxy.CountServiceJavaassistProxy extends java.lang.Object implements com.alibaba.test.performance.dynamicproxy.CountService{ public com.alibaba.test.performance.dynamicproxy.CountService delegate; public com.alibaba.test.performance.dynamicproxy.CountServiceJavaassistProxy(); Code: 0: aload_0 1: invokespecial #12; //Method java/lang/Object."":()V 4: return public int count(); Code: 0: aload_0 1: getfield #19; //Field delegate:Lcom/alibaba/test/performance/dynamicproxy/CountService; 4: invokeinterface #21, 1; //InterfaceMethod com/alibaba/test/performance/dynamicproxy/CountService.count:()I 9: ireturn }
(6) 用ASM自行生成的字节码:
public class com.alibaba.test.performance.dynamicproxy.CountServiceAsmProxy extends java.lang.Object implements com.alibaba.test.performance.dynamicproxy.CountService{ public com.alibaba.test.performance.dynamicproxy.CountService delegate; public com.alibaba.test.performance.dynamicproxy.CountServiceAsmProxy(); Code: 0: aload_0 1: invokespecial #10; //Method java/lang/Object."":()V 4: return public int count(); Code: 0: aload_0 1: getfield #16; //Field delegate:Lcom/alibaba/test/performance/dynamicproxy/CountService; 4: invokeinterface #18, 1; //InterfaceMethod com/alibaba/test/performance/dynamicproxy/CountService.count:()I 9: ireturn }
评论
13 楼
skzr.org
2017-07-30
如果要用可以参考如下
我的测试结果:神舟K590s Core i7-3630QM四核, 24G DDR3,
jvm: jdk1.8, -client -Xms2g -Xmx2g
- Spring体系,建议采用spring-aop cglib实现
- Javassist(bytecode):性能和ASM差不多,但是比ASM容易编写
我的测试结果:神舟K590s Core i7-3630QM四核, 24G DDR3,
jvm: jdk1.8, -client -Xms2g -Xmx2g
Run NO Proxy: 37 ms, 38,109,875 t/s Run JDK Proxy: 85 ms, 16,589,004 t/s Run CGLIB Proxy: 52 ms, 27,116,642 t/s Run Spring interface Proxy: 205 ms, 6,878,367 t/s Run Spring class Proxy: 38 ms, 37,106,984 t/s Run JAVAASSIST Proxy: 108 ms, 13,056,161 t/s Run JAVAASSIST Bytecode Proxy: 39 ms, 36,155,523 t/s Run ASM Bytecode Proxy: 39 ms, 36,155,523 t/s
xiaoxr 写道
测试机器:ryzen7 1700, 16G DDR4 2400运行用例的结果:
Create JDK Proxy: 5 ms
Create CGLIB Proxy: 82 ms
Create JAVAASSIST Proxy: 32 ms
Create JAVAASSIST Bytecode Proxy: 45 ms
Create ASM Proxy: 1 ms
================
Run JDK Proxy: 41 ms, 34,391,839 t/s
Run CGLIB Proxy: 57 ms, 24,737,989 t/s
Run JAVAASSIST Proxy: 265 ms, 5,321,001 t/s
Run JAVAASSIST Bytecode Proxy: 56 ms, 25,179,739 t/s
Run ASM Bytecode Proxy: 52 ms, 27,116,642 t/s
----------------
Run JDK Proxy: 73 ms, 19,315,964 t/s
Run CGLIB Proxy: 23 ms, 61,307,191 t/s
Run JAVAASSIST Proxy: 223 ms, 6,323,163 t/s
Run JAVAASSIST Bytecode Proxy: 45 ms, 31,334,786 t/s
Run ASM Bytecode Proxy: 46 ms, 30,653,595 t/s
----------------
Run JDK Proxy: 62 ms, 22,742,990 t/s
Run CGLIB Proxy: 51 ms, 27,648,341 t/s
Run JAVAASSIST Proxy: 264 ms, 5,341,156 t/s
Run JAVAASSIST Bytecode Proxy: 46 ms, 30,653,595 t/s
Run ASM Bytecode Proxy: 46 ms, 30,653,595 t/s
----------------
版本:jdk:1.8.0_131, cglib:3.2.4, javassist:3.12.1GA, ASM: 5.1
结论:JDK和cglib的效率与ASM已经不再是数量级的差距,尤其是jdk8进步非常大 ,javassist代理依然是最慢的,从易用性角度还是选择jdk和cglib更好。
Create JDK Proxy: 5 ms
Create CGLIB Proxy: 82 ms
Create JAVAASSIST Proxy: 32 ms
Create JAVAASSIST Bytecode Proxy: 45 ms
Create ASM Proxy: 1 ms
================
Run JDK Proxy: 41 ms, 34,391,839 t/s
Run CGLIB Proxy: 57 ms, 24,737,989 t/s
Run JAVAASSIST Proxy: 265 ms, 5,321,001 t/s
Run JAVAASSIST Bytecode Proxy: 56 ms, 25,179,739 t/s
Run ASM Bytecode Proxy: 52 ms, 27,116,642 t/s
----------------
Run JDK Proxy: 73 ms, 19,315,964 t/s
Run CGLIB Proxy: 23 ms, 61,307,191 t/s
Run JAVAASSIST Proxy: 223 ms, 6,323,163 t/s
Run JAVAASSIST Bytecode Proxy: 45 ms, 31,334,786 t/s
Run ASM Bytecode Proxy: 46 ms, 30,653,595 t/s
----------------
Run JDK Proxy: 62 ms, 22,742,990 t/s
Run CGLIB Proxy: 51 ms, 27,648,341 t/s
Run JAVAASSIST Proxy: 264 ms, 5,341,156 t/s
Run JAVAASSIST Bytecode Proxy: 46 ms, 30,653,595 t/s
Run ASM Bytecode Proxy: 46 ms, 30,653,595 t/s
----------------
版本:jdk:1.8.0_131, cglib:3.2.4, javassist:3.12.1GA, ASM: 5.1
结论:JDK和cglib的效率与ASM已经不再是数量级的差距,尤其是jdk8进步非常大 ,javassist代理依然是最慢的,从易用性角度还是选择jdk和cglib更好。
12 楼
xiaoxr
2017-06-18
测试机器:ryzen7 1700, 16G DDR4 2400运行用例的结果:
Create JDK Proxy: 5 ms
Create CGLIB Proxy: 82 ms
Create JAVAASSIST Proxy: 32 ms
Create JAVAASSIST Bytecode Proxy: 45 ms
Create ASM Proxy: 1 ms
================
Run JDK Proxy: 41 ms, 34,391,839 t/s
Run CGLIB Proxy: 57 ms, 24,737,989 t/s
Run JAVAASSIST Proxy: 265 ms, 5,321,001 t/s
Run JAVAASSIST Bytecode Proxy: 56 ms, 25,179,739 t/s
Run ASM Bytecode Proxy: 52 ms, 27,116,642 t/s
----------------
Run JDK Proxy: 73 ms, 19,315,964 t/s
Run CGLIB Proxy: 23 ms, 61,307,191 t/s
Run JAVAASSIST Proxy: 223 ms, 6,323,163 t/s
Run JAVAASSIST Bytecode Proxy: 45 ms, 31,334,786 t/s
Run ASM Bytecode Proxy: 46 ms, 30,653,595 t/s
----------------
Run JDK Proxy: 62 ms, 22,742,990 t/s
Run CGLIB Proxy: 51 ms, 27,648,341 t/s
Run JAVAASSIST Proxy: 264 ms, 5,341,156 t/s
Run JAVAASSIST Bytecode Proxy: 46 ms, 30,653,595 t/s
Run ASM Bytecode Proxy: 46 ms, 30,653,595 t/s
----------------
版本:jdk:1.8.0_131, cglib:3.2.4, javassist:3.12.1GA, ASM: 5.1
结论:JDK和cglib的效率与ASM已经不再是数量级的差距,尤其是jdk8进步非常大 ,javassist代理依然是最慢的,从易用性角度还是选择jdk和cglib更好。
Create JDK Proxy: 5 ms
Create CGLIB Proxy: 82 ms
Create JAVAASSIST Proxy: 32 ms
Create JAVAASSIST Bytecode Proxy: 45 ms
Create ASM Proxy: 1 ms
================
Run JDK Proxy: 41 ms, 34,391,839 t/s
Run CGLIB Proxy: 57 ms, 24,737,989 t/s
Run JAVAASSIST Proxy: 265 ms, 5,321,001 t/s
Run JAVAASSIST Bytecode Proxy: 56 ms, 25,179,739 t/s
Run ASM Bytecode Proxy: 52 ms, 27,116,642 t/s
----------------
Run JDK Proxy: 73 ms, 19,315,964 t/s
Run CGLIB Proxy: 23 ms, 61,307,191 t/s
Run JAVAASSIST Proxy: 223 ms, 6,323,163 t/s
Run JAVAASSIST Bytecode Proxy: 45 ms, 31,334,786 t/s
Run ASM Bytecode Proxy: 46 ms, 30,653,595 t/s
----------------
Run JDK Proxy: 62 ms, 22,742,990 t/s
Run CGLIB Proxy: 51 ms, 27,648,341 t/s
Run JAVAASSIST Proxy: 264 ms, 5,341,156 t/s
Run JAVAASSIST Bytecode Proxy: 46 ms, 30,653,595 t/s
Run ASM Bytecode Proxy: 46 ms, 30,653,595 t/s
----------------
版本:jdk:1.8.0_131, cglib:3.2.4, javassist:3.12.1GA, ASM: 5.1
结论:JDK和cglib的效率与ASM已经不再是数量级的差距,尤其是jdk8进步非常大 ,javassist代理依然是最慢的,从易用性角度还是选择jdk和cglib更好。
11 楼
lovearpu
2016-11-25
[color=gray][b]
[/b][/color]
[flash=200,200][url][img][list] |
[*]
|
[/list][/img][/url][/flash] |
" target="_blank">" />" target="_blank">" wmode="" quality="high" menu="false" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="200" height="200"> |
10 楼
wynlqxm
2016-08-19
哥,我看你贴出的【JDK生成的字节码】看到的都是/Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class等等反射相关的api。为什么您还是觉得“要注意的是JDK也是通过字节码生成来实现动态代理的,而不是反射”,可否解释下。谢谢。打扰了。
static {} throws ; Code: 0: ldc #70; //String java.lang.Object 2: invokestatic #76; //Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class; 5: ldc #77; //String equals 7: iconst_1 8: anewarray #72; //class java/lang/Class 11: dup 12: iconst_0 13: ldc #70; //String java.lang.Object 15: invokestatic #76; //Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class; 18: aastore 19: invokevirtual #81; //Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method; 22: putstatic #20; //Field m1:Ljava/lang/reflect/Method; 25: ldc #83; //String com.alibaba.test.performance.dynamicproxy.CountService 27: invokestatic #76; //Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class; 30: ldc #84; //String count 32: iconst_0 33: anewarray #72; //class java/lang/Class 36: invokevirtual #81; //Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method; 39: putstatic #50; //Field m3:Ljava/lang/reflect/Method; 42: ldc #70; //String java.lang.Object 44: invokestatic #76; //Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
9 楼
北冥郎
2014-12-15
楼主所说JDK也是通过字节码生成来实现动态代理的,而不是反射。这个不太理解,JdkHandler中的 return method.invoke(delegate, objects); 这就用到了反射啊。
另外一个问题,cglib和javassit动态生成字节码无法在android的dvm下使用,如果JDK的Proxy也是生成字节码,那应该也不能在android下使用,但JDK的Proxy确可以在android下使用。
有没有大神帮推荐一个android下实现AOP比较好的方式(除了JDK的Proxy),谢谢。
另外一个问题,cglib和javassit动态生成字节码无法在android的dvm下使用,如果JDK的Proxy也是生成字节码,那应该也不能在android下使用,但JDK的Proxy确可以在android下使用。
有没有大神帮推荐一个android下实现AOP比较好的方式(除了JDK的Proxy),谢谢。
8 楼
FlyAway2
2013-09-04
都是强人啊
7 楼
qicen
2013-05-24
经过仔细的思考,发现性能的根本原因还是在于反射。
JdkHandler中的 return method.invoke(delegate, objects); 是影响性能的关键。
如果JAVAASSIST Bytecode Proxy生成的代理类,也是通过JdkHanlder去实现的话,性能就和JDK自身的动态代理没什么区别了。
JdkHandler中的 return method.invoke(delegate, objects); 是影响性能的关键。
如果JAVAASSIST Bytecode Proxy生成的代理类,也是通过JdkHanlder去实现的话,性能就和JDK自身的动态代理没什么区别了。
6 楼
qicen
2013-05-22
学习了,文章写的非常好。
不过如果用JAVAASSIST Bytecode Proxy去写一个共同的代理类的话,效率和JDK 的动态代理类是差不多的。我是用dubbo里的这个类去做的测试:com.alibaba.dubbo.common.bytecode.Proxy
private static CountService createJavassistBytecodeDynamicProxy(CountService delegate) throws Exception {
return (CountService) com.alibaba.dubbo.common.bytecode.Proxy.getProxy(CountService.class).newInstance(new JdkHandler(delegate));
}
这是测试结果:
Create JDK Proxy: 16 ms
Create JAVAASSIST Proxy: 47 ms
Create JAVAASSIST Bytecode Proxy: 94 ms
================
Run JDK Proxy: 952 ms, 1,481,161 t/s
Run JAVAASSIST Proxy: 1498 ms, 941,298 t/s
Run JAVAASSIST Bytecode Proxy: 999 ms, 1,411,476 t/s
----------------
Run JDK Proxy: 984 ms, 1,432,993 t/s
Run JAVAASSIST Proxy: 1483 ms, 950,819 t/s
Run JAVAASSIST Bytecode Proxy: 1108 ms, 1,272,622 t/s
----------------
Run JDK Proxy: 1015 ms, 1,389,227 t/s
Run JAVAASSIST Proxy: 1436 ms, 981,939 t/s
Run JAVAASSIST Bytecode Proxy: 1109 ms, 1,271,474 t/s
----------------
不过如果用JAVAASSIST Bytecode Proxy去写一个共同的代理类的话,效率和JDK 的动态代理类是差不多的。我是用dubbo里的这个类去做的测试:com.alibaba.dubbo.common.bytecode.Proxy
private static CountService createJavassistBytecodeDynamicProxy(CountService delegate) throws Exception {
return (CountService) com.alibaba.dubbo.common.bytecode.Proxy.getProxy(CountService.class).newInstance(new JdkHandler(delegate));
}
这是测试结果:
Create JDK Proxy: 16 ms
Create JAVAASSIST Proxy: 47 ms
Create JAVAASSIST Bytecode Proxy: 94 ms
================
Run JDK Proxy: 952 ms, 1,481,161 t/s
Run JAVAASSIST Proxy: 1498 ms, 941,298 t/s
Run JAVAASSIST Bytecode Proxy: 999 ms, 1,411,476 t/s
----------------
Run JDK Proxy: 984 ms, 1,432,993 t/s
Run JAVAASSIST Proxy: 1483 ms, 950,819 t/s
Run JAVAASSIST Bytecode Proxy: 1108 ms, 1,272,622 t/s
----------------
Run JDK Proxy: 1015 ms, 1,389,227 t/s
Run JAVAASSIST Proxy: 1436 ms, 981,939 t/s
Run JAVAASSIST Bytecode Proxy: 1109 ms, 1,271,474 t/s
----------------
5 楼
javatar
2012-02-27
chenchao051 写道
哈哈,至少博主和Gavin King做了相同的选择:
Hibernate, Environment类:
Hibernate, Environment类:
private static BytecodeProvider buildBytecodeProvider(String providerName){ if ( "javassist".equals( providerName ) ) { return new org.hibernate.bytecode.javassist.BytecodeProviderImpl(); }else if ( "cglib".equals( providerName ) ) { return new org.hibernate.bytecode.cglib.BytecodeProviderImpl(); } .......
Gavin King也是RedHat旗下的,当然选同宗的了,呵呵。
4 楼
chenchao051
2012-02-27
哈哈,至少博主和Gavin King做了相同的选择:
Hibernate, Environment类:
Hibernate, Environment类:
private static BytecodeProvider buildBytecodeProvider(String providerName){ if ( "javassist".equals( providerName ) ) { return new org.hibernate.bytecode.javassist.BytecodeProviderImpl(); }else if ( "cglib".equals( providerName ) ) { return new org.hibernate.bytecode.cglib.BytecodeProviderImpl(); } .......
3 楼
javatar
2012-02-23
billykinggym 写道
请问 用动态代理生成的bytecode是如何从jvm里导出来的?谢谢
可以用:
javap -c 类名
2 楼
billykinggym
2012-02-14
请问 用动态代理生成的bytecode是如何从jvm里导出来的?谢谢
1 楼
agapple
2011-03-31
这样的测试对cglib不公平,因为javassit采用的是直接调用,而cglib走了methodProxy.invoke(),说白了还是反射调用。
可以实施cglib的直接调用,比如使用的Dispatcher或则LazyLoader。最后的生成的字节就是一个直接调用,性能上就可以和javassist持平。
可以实施cglib的直接调用,比如使用的Dispatcher或则LazyLoader。最后的生成的字节就是一个直接调用,性能上就可以和javassist持平。
class DirectService implements Dispatcher { public Object loadObject() throws Exception { return service; } }
发表评论
-
能力成长模型
2012-05-09 00:28 22939最近看了温伯格1986年出版的《技术领导之路》, 很老的书,讲 ... -
以HTTL为例讲讲模块分包&领域模型&扩展框架
2011-10-09 20:08 16750注:该博客内容已加入 ... -
使用Map参数的Webx3扩展
2011-08-28 02:10 5917因Webx3是开源的,所以把这个简单的Webx3扩展发在博客上 ... -
Netty内存泄露
2011-08-02 20:09 24967转于自己在公司的Blog: ... -
Grizzly和Netty以及Mina简单性能对比
2011-07-17 02:48 29745转于自己在公司的Blog: http://pt.alibaba ... -
RPC框架几行代码就够了
2011-07-14 00:34 90195转于自己在公司的Blog: http://pt.alibaba ... -
魔鬼在细节中
2011-05-24 14:50 32255转于自己在公司的Blog: ... -
Dubbo扩展点重构
2011-05-12 22:09 38897转于自己在公司的Blog: http://pt.alibaba ... -
配置设计
2011-03-09 23:41 23586转于自己在公司的Blog: ... -
[转]HTML5设计原理
2011-03-09 22:57 7805Jeremy Keith在 Fronteers 2010 ... -
Hessian序列化不设SerializerFactory性能问题
2010-12-27 11:38 6474转于自己在公司的Blog: http://pt.alibaba ... -
防痴呆设计
2010-11-05 18:58 17685转于自己在公司的Blog: ... -
负载均衡扩展接口重构
2010-11-05 18:53 8757转于自己在公司的Blog: ... -
分布式服务框架常被质疑的价值
2010-11-05 18:52 5734转于自己在公司的Blog: http://pt.alibaba ... -
Hessian3.2.1在序列化32.5k字符串时的问题
2010-11-05 18:49 7255转于自己在公司的Blog: http://pt.alibaba ... -
一些设计上的基本常识
2010-07-05 19:28 27736转于自己在公司的Blog: ... -
谈谈扩充式扩展与增量式扩展
2010-06-12 19:46 19385转于自己在公司的Blog: http://pt.alibaba ... -
Scaling Architecture
2010-02-25 10:31 4118Scaling Second Life: http://p ... -
EBay SOA
2010-02-23 18:23 4800EBay SOA PPT -
服务化基础设施
2009-11-15 23:11 6282服务化,也可以叫SOA, ...
相关推荐
Android动态加载Apk-插件化技术(动态代理方案) 一. 什么是插件化 1. 主App(宿主App)加载插件apk的实现 2. 每个业务组件模块形成一个独立的Apk, 然后通过主App动态加载部署业务组件模块Apk的一种方案 二.插件化的...
8. **性能对比**:相对于JDK的动态代理,CGLib在某些场景下性能更优,因为它避免了接口调用的额外开销。然而,由于涉及到字节码操作,CGLib在初始化阶段可能比JDK代理慢。 9. **使用示例**:创建一个动态代理通常...
本篇文章将详细探讨如何通过Java的动态代理机制来模拟Spring AOP的核心概念。 首先,让我们了解什么是动态代理。在Java中,动态代理主要由`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口...
在构建高性能的Windows Communication Foundation(WCF)解决方案时,我们需要关注多个关键方面,这些方面将直接影响服务的性能、效率和可扩展性。本篇将详细探讨传输层、序列化器、编码器的选择以及客户端和服务端...
4. **性能分析**:从计算开销和通信开销两个方面评估该方案的效率,并与其他相关签名方案进行比较。结果显示,所提出的ABPS方案在保持与现有方案相似的通信开销的同时,显著减少了计算成本。 #### 相关工作概述 - ...
【标题】中所提及的“高效的代理多重盲签名方案”可能意味着所提出的方案在满足安全性要求的同时,具有更好的性能表现。这可能意味着该方案在保持高强度安全性的同时,通过优化算法,降低了计算资源的消耗,并减少了...
2. 独特的接收机设计,低功耗和高性能。 3. 单电源设计可以节省BOM成本。 4. 可编程的SSC可以降低电磁干扰。 5. VGA的输出幅度自动校准算法,可以兼容各种阻抗。 6. DisplayPort自适应均衡算法,适应不同衰减的电缆...
此外,文章还对比了Linux内核编程和用户态编程的优缺点,强调了内核编程在性能优化上的优势。通过实际测试数据,KHttpProxyd的性能表现明显优于其他HTTP代理软件,证明了这种设计和实现策略的有效性。 总的来说,...
java8 stream 源码 Java各种开源库积累 好好学习,天天向上。 演示内容 1)src/main/java org.xpen.audio 播放各种声音格式ogg,mp3,ape,flac org.xpen.chess.puzzle8 ...动态代理方案性能对比,比较了J
在本方案中,Web Polygraph将被用来比较硬件MWG(McAfee Web Gateway)和软件MWG的性能差异。 测试环境基于CentOS 6.5 X86-64操作系统,这是由于Linux系统提供了稳定的基础,并且能够支持Web Polygraph的运行。为了...
代理模式可以用于性能监控或拦截操作,提高代码的灵活性。这些模式的合理运用能提高代码的可读性和可维护性,间接提升性能。 在实际项目中,我们还需要借助各种性能分析工具,如JProfiler、VisualVM等,它们能帮助...
- **性能差异**:NAT因为工作在网络层,通常比工作在更高层的代理服务器速度更快。但如果代理服务器启用了缓存功能,则情况可能有所不同。 - **协议支持**:NAT支持更多的上层协议,几乎涵盖了所有的常见应用层协议...
实验部分可能会展示在不同场景下的性能比较,包括不同基函数下的轨迹质量和规划效率。此外,可能会对比集中式和去中心化方法的优劣,以证明MADER在实时性和安全性方面的优势。 IV. 结论与未来工作 MADER的提出为...
对于性能对比,LVS在处理大量连接时可能有优势,而Nginx在处理动态内容和复杂HTTP逻辑时更出色。 演讲可能详细讲解了LVS和Nginx的安装、配置、优化方法,以及在实际项目中如何选择合适的负载均衡策略。同时,通过...
简介 Ruby On Rails 框架自它提出之日起就受到广泛关注,在“不要重复自己”,“约定优于配置”等思想的指导下,Rails 带给 Web 开发者的是极高的开发效率。 ActiveRecord 的灵活让你再也不用配置繁琐的 Hibernate ...
反向代理服务器是提高WEB服务器性能和安全性的解决方案。它位于本地WEB服务器和Internet之间,承担对原始WEB服务器的静态页面的请求,防止原始服务器过载。反向代理服务器可以降低WEB服务器的负载,提高访问速度,...
当一个类没有实现接口时,CGLIB可以作为JDK动态代理的一种替代方案。它创建目标类的子类,并在子类中拦截方法调用,从而实现动态代理。 2. **与ASM的关系**: - CGLIB底层依赖于ASM库来生成和操作字节码。ASM是一...
经常有朋友困扰于Android上面实现推送的技术,希望知道各种方案的优缺点、性能、开发难度等,于是特意写了这篇文章。 方案一: Google官方的服务: 但,通过对比研究发现C2DM机制存在以下缺点: 1)GCM要求Android...
- **共享存储和集群代理**:利用共享存储技术与集群代理软件配合,可以实现在多台服务器间的数据共享和自动故障转移。 - **高可用网络设备**:如Dolphin SCI互连适配器,能够提供高性能和低延迟的数据传输,非常适合...