先在mavne项目里添加cglib库
maven仓库搜索cglib版本
maven地址:http://mvnrepository.com/
点击最新的版本 3.2.5
复制到pom.xml dependencies 标签下
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> </dependency>
接着在TestProxy.class添加方法
public static void testCglib() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserServiceImpl.class); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { return proxy.invokeSuper(obj, args); } }); UserService impTarget = (UserService) enhancer.create(); run("cglib",impTarget); }
public static void main(String[] args) { testNative(); testJdk(); testCglib(); }
继续运行测试:
native: 177 native: 191 native: 132 native: 179 native: 132 native: 152 native: 183 native: 131 native: 133 native: 132 native: 131 native: 133 native: 132 native: 132 native: 133
jdk: 218 jdk: 172 jdk: 172 jdk: 173 jdk: 172 jdk: 172 jdk: 172 jdk: 172 jdk: 173 jdk: 172 jdk: 174 jdk: 172 jdk: 172 jdk: 172 jdk: 173
cglib: 294 cglib: 271 cglib: 271 cglib: 284 cglib: 270 cglib: 270 cglib: 268 cglib: 268 cglib: 269 cglib: 268 cglib: 269 cglib: 269 cglib: 280 cglib: 268 cglib: 273
可以看出 cglib比jdk还要慢
我们来查看下生成的class指令有多少条
先加一行System.in.read(); 防止程序退出
public static void main(String[] args) throws IOException { testNative(); testJdk(); testCglib(); System.in.read(); }
运行HSDB工具
1)、打开cmd窗口,运行命令:java -classpath "%JAVA_HOME%/lib/sa-jdi.jar" sun.jvm.hotspot.HSDB
2)、点击file菜单下第一项
弹出
3)、打开任务管理器,在任务管理器菜单查看->选择列->勾选PID
找到当前运行java程序的进程号pid,输入到上图的文本框中,点击ok弹出
4)、点击工具(tools)菜单下的第一项Class Browser。弹出
5)、输入包名TestProxy回车.只要看cglib生成的动态类
只要看 super class 实现类
6)、点击Create .class File,在HSDB工具运行目录下下生产cglib动态代理类
用jd-gui打开
逻辑跟JDK差不多,只要不同部分
public final String getName(int paramInt) { MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0; if (tmp4_1 == null) { tmp4_1; CGLIB$BIND_CALLBACKS(this); } MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0; if (tmp17_14 != null) { return (String)tmp17_14.intercept(this, CGLIB$getName$0$Method, new Object[] { new Integer(paramInt) }, CGLIB$getName$0$Proxy); } return super.getName(paramInt); }
CGLIB$CALLBACK_0 是cglib MethodInterceptor 对象
由于jd-gui无法完全反编译 看不到CGLIB$getName$0$Proxy MethodProxy 对象是如何生成的
我们用javap 看下 getName 生成多少条指令大概知道为什么会慢
javap -v TestProxy$UserServiceImpl$$EnhancerByCGLIB$$aa69a57.class > d.txt
public final java.lang.String getName(int); descriptor: (I)Ljava/lang/String; flags: ACC_PUBLIC, ACC_FINAL Code: stack=9, locals=2, args_size=2 0: aload_0 1: getfield #40 // Field CGLIB$CALLBACK_0:Lnet/sf/cglib/proxy/MethodInterceptor; 4: dup 5: ifnonnull 17 8: pop 9: aload_0 10: invokestatic #44 // Method CGLIB$BIND_CALLBACKS:(Ljava/lang/Object;)V 13: aload_0 14: getfield #40 // Field CGLIB$CALLBACK_0:Lnet/sf/cglib/proxy/MethodInterceptor; 17: dup 18: ifnull 53 21: aload_0 22: getstatic #46 // Field CGLIB$getName$0$Method:Ljava/lang/reflect/Method; 25: iconst_1 26: anewarray #48 // class java/lang/Object 29: dup 30: iconst_0 31: iload_1 32: new #50 // class java/lang/Integer 35: dup_x1 36: swap 37: invokespecial #53 // Method java/lang/Integer."<init>":(I)V 40: aastore 41: getstatic #55 // Field CGLIB$getName$0$Proxy:Lnet/sf/cglib/proxy/MethodProxy; 44: invokeinterface #61, 5 // InterfaceMethod net/sf/cglib/proxy/MethodInterceptor.intercept:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object; 49: checkcast #63 // class java/lang/String 52: areturn 53: aload_0 54: iload_1 55: invokespecial #38 // Method com/eyu/onequeue/TestProxy$UserServiceImpl.getName:(I)Ljava/lang/String; 58: areturn
从数量上看比jdk生成的指令差不多有二倍多,慢是必然的,但cglib比jdk1.6快,原因是jdk1.6生成差不多有上百代指令
顺便说下spring 代理有两种模式 1.cglib 2.jdk
proxyTargetClass 属性,设置为true,则使用CGLIB代理,此属性默认为false,使用JDK动态代理
<aop:scoped-proxy proxy-target-class="true" />