cglib动态代理实现原理
来源:互联网 发布:大数据征信查询入口app 编辑:程序博客网 时间:2024/04/30 14:58
cglib是一个字节码操纵库,底层基于ASM框架。虽然JDK同样提供了动态代理功能,但是必须将需要代理的方法写在接口中,由主体类继承,很不灵活,而且性能不如cglib。下面是一个使用cglib动态代理的例子。
主体类:
public class MyClass {public void print() { System.out.println("I'm in MyClass.print!"); } }
代理类:
public class Main { public static void main(String[] args) {System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, System.getProperty("user.dir") + "/bin");Enhancer enhancer = new Enhancer();enhancer.setSuperclass(MyClass.class);enhancer.setCallback(new MethodInterceptorImpl());MyClass my = (MyClass) enhancer.create();my.print();} private static class MethodInterceptorImpl implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// log somethingSystem.out.println(method + " intercepted!");proxy.invokeSuper(obj, args);return null;}}}
实现原理:
1.操纵字节码,生成Myclass的子类。将MyClass的子类的字节码反编译之后,看起来会接近这个等价类:
class MyClass$$EnhancerByCGLIB extends MyClass{private MethodInterceptor methodInterceptor;public void print() throws Throwable {Class localClass = Class.forName("cgproxy.MyClass$$EnhancerByCGLIB"); ClassLoader classLoader = localClass.getClassLoader(); Method method = Class.forName("cgproxy.MyClass").getDeclaredMethod("print", new Class[0]); MethodProxy methodProxy = MethodProxy.create(classLoader, method.getDeclaringClass(), localClass, "()V", "print", "CGLIB$print");methodInterceptor.intercept(this, method, null, methodProxy);}public void CGLIB$print() {super.print();}}
需要注意的是,继承自Object的方法都会按相同的方式生成字节码,wait,notify方法除外,因此MyClass.toString()也会被代理。
这是直接由字节码反编译的结果,可以忽略
public class MyClass$$EnhancerByCGLIB$$1e2eda10 extends MyClass implements Factory {static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); Class localClass; CGLIB$emptyArgs = new Object[0]; ClassLoader tmp27_17 = (localClass = Class.forName("cgproxy.MyClass$$EnhancerByCGLIB$$1e2eda10")).getClassLoader(); CGLIB$print$0$0$Proxy = MethodProxy.create(tmp27_17, (1e2eda10.CGLIB$print$0$0$Method = Class.forName("cgproxy.MyClass").getDeclaredMethod("print", new Class[0])).getDeclaringClass(), localClass, "()V", "print", "CGLIB$print$0$0"); return;}final void CGLIB$print$0$0() {super.print();}public final void print() {MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;if (tmp4_1 == null){tmp4_1;CGLIB$BIND_CALLBACKS(this);}if (this.CGLIB$CALLBACK_0 != null)return; super.print();}}
2.执行代码,enhancer.create返回的是MyClass$$EnhancerByCGLIB类的实例,my.print()实际调用的是MyClass$$EnhancerByCGLIB.print(),然后会被MethodInterceptor代理类拦截
3.完成前置代理
4.调用主体类的print()方法:MethodProxy.invokeSuper(MyClass$$EnhancerByCGLIB, Object[]), 这是MethodProxy的相关代码
4.调用主体类的print()方法:MethodProxy.invokeSuper(MyClass$$EnhancerByCGLIB, Object[]), 这是MethodProxy的相关代码
public class MethodProxy {private FastClass f2;private int i2; public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { return f2.invoke(i2, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } }}
FastClass也是操纵字节码动态生成的类,invoke()会根据事先建立的int值与方法之间的映射,通过int索引访问方法,字节码如下(可能是JD-GUI支持的jdk版本太低了,这一段不能反编译成Java代码)
public Object invoke(int paramInt, Object paramObject, Object[] paramArrayOfObject)
throws InvocationTargetException { // Byte code: // 0: aload_2//load paramObject到oprand stack // 1: checkcast 152cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10//类型检查 // 4: iload_1//load paramInt索引到opran stack // 5: tableswitchdefault:+387 -> 392, 0:+123->128, 1:+138->143, 2:+142->147, 3:+154->159, 4:+176->181, 5:+186->191, 6:+196->201//跳转 // 129: iconst_0 // 130: aaload // 131: invokevirtual 153cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:equals(Ljava/lang/Object;)Z // 134: new 155java/lang/Boolean // 137: dup_x1 // 138: swap // 139: invokespecial 158java/lang/Boolean:<init>(Z)V // 142: areturn // 143: invokevirtual 159cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:toString()Ljava/lang/String; // 146: areturn // 147: invokevirtual 160cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:hashCode()I // 150: new 162java/lang/Integer // 153: dup_x1 // 154: swap // 155: invokespecial 165java/lang/Integer:<init>(I)V // 158: areturn // 159: aload_3 // 160: iconst_0 // 161: aaload // 162: checkcast 167[Ljava/lang/Class; // 165: aload_3 // 166: iconst_1 // 167: aaload // 168: checkcast 169[Ljava/lang/Object; // 171: aload_3 // 172: iconst_2 // 173: aaload // 174: checkcast 171[Lnet/sf/cglib/proxy/Callback; // 177: invokevirtual 174cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object; // 180: areturn // 181: aload_3 // 182: iconst_0 // 183: aaload // 184: checkcast 176net/sf/cglib/proxy/Callback // 187: invokevirtual 179cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object; // 190: areturn // 191: aload_3 // 192: iconst_0 // 193: aaload // 194: checkcast 171[Lnet/sf/cglib/proxy/Callback; // 197: invokevirtual 182cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object; // 200: areturn // 201: invokevirtual 185cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:print()V//paramObject.print() // 204: aconst_null//将null压入oprand stack // 205: areturn//return}
5.方法返回,如果有后置增强的话,进行后置增强
Java字节代码增强(ASM)
JDK动态代理示例
html学得好,博客写到老,各种奇怪的字符都得手动删,囧
0 0
- Cglib实现动态代理原理
- Cglib实现动态代理原理
- cglib动态代理实现原理
- CGLib动态代理原理及实现
- CGLib动态代理原理及实现
- CGLib动态代理原理及实现
- 【转载】CGLib动态代理原理及实现
- CGLib动态代理原理及实现
- CGLib动态代理原理及实现
- CGLib动态代理原理及实现
- 【转载】CGLib动态代理原理及实现
- CGLib动态代理原理及实现
- CGLib动态代理原理及实现
- CGLib动态代理原理及实现
- CGLib动态代理原理及实现
- CGLib动态代理原理及实现
- CGLib动态代理原理及实现
- CGLib动态代理原理及实现
- Servlet及JSP解决中文乱码问题
- Spring、Struts2、Hibernate集成开…
- select挡住div的5种解决方法
- Grid View(网格视图)
- ASP.NET是如何在IIS下工作的
- cglib动态代理实现原理
- Input Controls(输入控件)
- notepad++ 不让文字下面的红线显示
- SQL SERVER灾难时备份结尾日志的两种方法(tail of log)
- static用法总结
- Buttons(按钮)
- UITextView换行
- Authorized users only. All activity may be monitored and reported.
- 实验室的第三周-忙碌的一周