CGLIB代理的使用与原理解析
CGLIB概述
Cglib代理
静态代理和JDK 代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理-这就是Cglib 代理。
JDK中提供的生成动态代理类的机制有个鲜明的特点是:
- 某个类必须有实现的接口
- 生成的代理类也只能代理某个类接口定义的方法。
那么如果一个类没有实现接口怎么办呢?
这就有CGLIB的诞生了,前面说的JDK的动态代理的实现方式是实现相关的接口成为接口的实现类,那么我们自然可以想到用继承的方式实现相关的代理类。
Cglib 代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展, 有些书也将Cglib 代理归属到动态代理。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法最好不要声明成final, static方法,private方法,final方法是不能被代理的
Cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展java 类与实现java 接口.它广泛的被许多AOP 的框架使用,例如Spring AOP,实现方法拦截。
在AOP 编程中如何选择代理模式:
- 目标对象需要实现接口,用JDK 代理
- 目标对象不需要实现接口,用Cglib 代理
Cglib 包的底层是通过使用字节码处理框架ASM 来转换字节码并生成新的类
应用案例
pom依赖
<!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> </dependency>
在JDK动态代理的代码基础上进行修改
① 测试客户端
import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class TestCglibProxy { public static void main(String[] args) { //创建一个被代理类的对象 SuperMan man = new SuperMan(); CGLibProxy cgLibProxy = new CGLibProxy(); //返回一个代理类的对象--注意这里现在传入的是实现类 Object obj = cgLibProxy.getProxyInstance(man); System.out.println(obj.getClass()); //class com.web.test.SuperMan$$EnhancerByCGLIB$$3be74240 Human hu = (Human)obj; //通过代理类的对象调用重写的抽象方法 hu.info(); System.out.println(); hu.fly(); } }
② 自定义CGLibProxy
class CGLibProxy implements MethodInterceptor { // CGLib需要代理的目标对象 private Object targetObject; public Object getProxyInstance(Object obj) { this.targetObject = obj; //1. 创建一个工具类 Enhancer enhancer = new Enhancer(); // 2.设置父类--可以是类或者接口 enhancer.setSuperclass(obj.getClass()); //3. 设置回调函数 enhancer.setCallback(this); //4. 创建子类对象,即代理对象 Object proxyObj = enhancer.create(); // 返回代理对象 return proxyObj; } public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object obj = null; //模拟功能增强 HumanUtil humanUtil = new HumanUtil(); humanUtil.method1(); // 执行目标目标对象方法 obj = method.invoke(targetObject, args); //模拟功能增强 humanUtil.method2(); return obj; } }
HumanUtil 如下:
class HumanUtil { public void method1() { System.out.println("=======方法一======="); } public void method2() { System.out.println("=======方法二======="); } }
测试结果
如下所示:
class com.web.test.SuperMan$$EnhancerByCGLIB$$3be74240
=======方法一=======
我是超人!我怕谁!
=======方法二=======
=======方法一=======
I believe I can fly!
=======方法二=======
获取代理类源码
有了源码才好分析验证cglib生成的代理类究竟是个什么样子?这里主要用到下面代码:
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path);
修改上面的main方法如下:
public static void main(String[] args) { SuperMan man = new SuperMan();//创建一个被代理类的对象 // 添加如下代码,获取代理类源文件 String path = CGLibProxy.class.getResource(".").getPath(); System.out.println(path); System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path); CGLibProxy cgLibProxy = new CGLibProxy(); Object obj = cgLibProxy.bind(man);//返回一个代理类的对象 System.out.println(obj.getClass()); //class com.web.test.SuperMan$$EnhancerByCGLIB$$3be74240 Human hu = (Human)obj; hu.info();//通过代理类的对象调用重写的抽象方法 System.out.println(); hu.fly(); }
测试结果如下:
生成的代理类名字 SuperMan$$EnhancerByCGLIB$$3be74240 ,源码如下:
可以直接在//javare.cn/网站下在线反编译。
package com.web.test; import com.web.test.SuperMan; import java.lang.reflect.Method; import net.sf.cglib.core.ReflectUtils; import net.sf.cglib.core.Signature; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Factory; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; //继承目标被代理类 public class SuperMan$$EnhancerByCGLIB$$3be74240 extends SuperMan implements Factory { private boolean CGLIB$BOUND; public static Object CGLIB$FACTORY_DATA; private static final ThreadLocal CGLIB$THREAD_CALLBACKS; private static final Callback[] CGLIB$STATIC_CALLBACKS; private MethodInterceptor CGLIB$CALLBACK_0; private static Object CGLIB$CALLBACK_FILTER; private static final Method CGLIB$info$0$Method; private static final MethodProxy CGLIB$info$0$Proxy; private static final Object[] CGLIB$emptyArgs; private static final Method CGLIB$fly$1$Method; private static final MethodProxy CGLIB$fly$1$Proxy; private static final Method CGLIB$equals$2$Method; private static final MethodProxy CGLIB$equals$2$Proxy; private static final Method CGLIB$toString$3$Method; private static final MethodProxy CGLIB$toString$3$Proxy; private static final Method CGLIB$hashCode$4$Method; private static final MethodProxy CGLIB$hashCode$4$Proxy; private static final Method CGLIB$clone$5$Method; private static final MethodProxy CGLIB$clone$5$Proxy; // 一系列私有静态常量定义 // 常量初始化 static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; Class var0 = Class.forName("com.web.test.SuperMan$$EnhancerByCGLIB$$3be74240"); Class var1; Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods()); CGLIB$equals$2$Method = var10000[0]; CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2"); CGLIB$toString$3$Method = var10000[1]; CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3"); CGLIB$hashCode$4$Method = var10000[2]; CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4"); CGLIB$clone$5$Method = var10000[3]; CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5"); var10000 = ReflectUtils.findMethods(new String[]{"info", "()V", "fly", "()V"}, (var1 = Class.forName("com.web.test.SuperMan")).getDeclaredMethods()); CGLIB$info$0$Method = var10000[0]; CGLIB$info$0$Proxy = MethodProxy.create(var1, var0, "()V", "info", "CGLIB$info$0"); CGLIB$fly$1$Method = var10000[1]; CGLIB$fly$1$Proxy = MethodProxy.create(var1, var0, "()V", "fly", "CGLIB$fly$1"); } //绑定MethodInterceptor callback的方法会额外实现一个和原方法一模一样的方法 final void CGLIB$info$0() { super.info(); } // 代理对象的方法调用将会转发到代理对象的intercept方法 public final void info() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if(var10000 != null) { var10000.intercept(this, CGLIB$info$0$Method, CGLIB$emptyArgs, CGLIB$info$0$Proxy); } else { super.info(); } } final void CGLIB$fly$1() { super.fly(); } public final void fly() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if(var10000 != null) { var10000.intercept(this, CGLIB$fly$1$Method, CGLIB$emptyArgs, CGLIB$fly$1$Proxy); } else { super.fly(); } } final boolean CGLIB$equals$2(Object var1) { return super.equals(var1); } public final boolean equals(Object var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if(var10000 != null) { Object var2 = var10000.intercept(this, CGLIB$equals$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy); return var2 == null?false:((Boolean)var2).booleanValue(); } else { return super.equals(var1); } } final String CGLIB$toString$3() { return super.toString(); } public final String toString() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null?(String)var10000.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy):super.toString(); } final int CGLIB$hashCode$4() { return super.hashCode(); } public final int hashCode() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if(var10000 != null) { Object var1 = var10000.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy); return var1 == null?0:((Number)var1).intValue(); } else { return super.hashCode(); } } final Object CGLIB$clone$5() throws CloneNotSupportedException { return super.clone(); } protected final Object clone() throws CloneNotSupportedException { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null?var10000.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy):super.clone(); } // 获取方法的 MethodProxy public static MethodProxy CGLIB$findMethodProxy(Signature var0) { String var10000 = var0.toString(); switch(var10000.hashCode()) { case -1271409118: if(var10000.equals("fly()V")) { return CGLIB$fly$1$Proxy; } break; case -508378822: if(var10000.equals("clone()Ljava/lang/Object;")) { return CGLIB$clone$5$Proxy; } break; case 1826985398: if(var10000.equals("equals(Ljava/lang/Object;)Z")) { return CGLIB$equals$2$Proxy; } break; case 1913648695: if(var10000.equals("toString()Ljava/lang/String;")) { return CGLIB$toString$3$Proxy; } break; case 1945358343: if(var10000.equals("info()V")) { return CGLIB$info$0$Proxy; } break; case 1984935277: if(var10000.equals("hashCode()I")) { return CGLIB$hashCode$4$Proxy; } } return null; } //无参构造器 public SuperMan$$EnhancerByCGLIB$$3be74240() { CGLIB$BIND_CALLBACKS(this); } public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) { CGLIB$THREAD_CALLBACKS.set(var0); } public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) { CGLIB$STATIC_CALLBACKS = var0; } private static final void CGLIB$BIND_CALLBACKS(Object var0) { SuperMan$$EnhancerByCGLIB$$3be74240 var1 = (SuperMan$$EnhancerByCGLIB$$3be74240)var0; if(!var1.CGLIB$BOUND) { var1.CGLIB$BOUND = true; Object var10000 = CGLIB$THREAD_CALLBACKS.get(); if(var10000 == null) { var10000 = CGLIB$STATIC_CALLBACKS; if(CGLIB$STATIC_CALLBACKS == null) { return; } } var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0]; } } public Object newInstance(Callback[] var1) { CGLIB$SET_THREAD_CALLBACKS(var1); SuperMan$$EnhancerByCGLIB$$3be74240 var10000 = new SuperMan$$EnhancerByCGLIB$$3be74240(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Callback var1) { CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1}); SuperMan$$EnhancerByCGLIB$$3be74240 var10000 = new SuperMan$$EnhancerByCGLIB$$3be74240(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) { CGLIB$SET_THREAD_CALLBACKS(var3); SuperMan$$EnhancerByCGLIB$$3be74240 var10000 = new SuperMan$$EnhancerByCGLIB$$3be74240; switch(var1.length) { case 0: var10000.<init>(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; default: throw new IllegalArgumentException("Constructor not found"); } } public Callback getCallback(int var1) { CGLIB$BIND_CALLBACKS(this); MethodInterceptor var10000; switch(var1) { case 0: var10000 = this.CGLIB$CALLBACK_0; break; default: var10000 = null; } return var10000; } public void setCallback(int var1, Callback var2) { switch(var1) { case 0: this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2; default: } } public Callback[] getCallbacks() { CGLIB$BIND_CALLBACKS(this); return new Callback[]{this.CGLIB$CALLBACK_0}; } // 初始化定义的callback public void setCallbacks(Callback[] var1) { this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0]; } // 这里,类加载的时候首先执行!!! static { CGLIB$STATICHOOK1(); } }
可以发现这个类继承自接口实现类–SuperMan,其在加载的时候会先进行一系列静态常量的初始化且在实例化的时候调用 CGLIB$BIND_CALLBACKS(this); 进行call back的绑定。
那么现在的情况就是我们的生成了一个代理类,这个代理类是我们需要代理的实现类的继承类。我们的被代理类的方法在这个代理类中帮我们重写了,并且全部变成了final的。同时覆盖了一些Object类中的方法。
以 info 这个方法举例,方法中会调用 MethodInterceptor 类中的 intercept 方法(也就是我们实现的逻辑的地方),同时把自己的Method对象,参数列表等传入进去。
两个小问题
如果代理的目标对象为接口行不行?·
接口中的方法代理类实现了,那么类中自定义的方法代理类是否也可以实现?
毫无疑问,cglib是基于类的动态代理,代理类继承自目标类, 类中的方法除了final自然可以继承 !
传入接口为代理对象进行测试
public class TestCglibProxy2 { public static void main(String[] args) { String path = CGLibProxy.class.getResource(".").getPath(); System.out.println(path); System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path); CGLibProxy2 cgLibProxy = new CGLibProxy2(); //返回一个代理类的对象--这里直接传入Human接口 Class!!! Object obj = cgLibProxy.getProxyInstance(Human.class); System.out.println(obj.getClass()); //class com.web.test.Human$$EnhancerByCGLIB$$9fc9106 Human hu = (Human)obj; hu.info();//通过代理类的对象调用重写的抽象方法 System.out.println(); hu.fly(); } } class CGLibProxy2 implements MethodInterceptor { public Object getProxyInstance(Class<?> obj) { Enhancer enhancer = new Enhancer(); // 这里传入Class enhancer.setSuperclass(obj); enhancer.setCallback(this); Object proxyObj = enhancer.create(); return proxyObj;// 返回代理对象 } public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object obj = null; //模拟功能增强 HumanUtil humanUtil = new HumanUtil(); humanUtil.method1(); // 执行目标目标对象方法--这里直接传入目标对象 obj = method.invoke(new SuperMan(), args); //模拟功能增强 humanUtil.method2(); return obj; } }
测试结果如下图:
此时生成的源码 Human$$EnhancerByCGLIB$$9fc9106 如下所示:
package com.web.test; import com.web.test.Human; import java.lang.reflect.Method; import net.sf.cglib.core.ReflectUtils; import net.sf.cglib.core.Signature; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Factory; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; //注意,这里变为了实现Human接口形式 public class Human$$EnhancerByCGLIB$$9fc9106 implements Human, Factory { private boolean CGLIB$BOUND; public static Object CGLIB$FACTORY_DATA; private static final ThreadLocal CGLIB$THREAD_CALLBACKS; private static final Callback[] CGLIB$STATIC_CALLBACKS; private MethodInterceptor CGLIB$CALLBACK_0; private static Object CGLIB$CALLBACK_FILTER; private static final Method CGLIB$equals$0$Method; private static final MethodProxy CGLIB$equals$0$Proxy; private static final Object[] CGLIB$emptyArgs; private static final Method CGLIB$toString$1$Method; private static final MethodProxy CGLIB$toString$1$Proxy; private static final Method CGLIB$hashCode$2$Method; private static final MethodProxy CGLIB$hashCode$2$Proxy; private static final Method CGLIB$clone$3$Method; private static final MethodProxy CGLIB$clone$3$Proxy; private static final Method CGLIB$info$4$Method; private static final MethodProxy CGLIB$info$4$Proxy; private static final Method CGLIB$fly$5$Method; private static final MethodProxy CGLIB$fly$5$Proxy; static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; Class var0 = Class.forName("com.web.test.Human$$EnhancerByCGLIB$$9fc9106"); Class var1; Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods()); CGLIB$equals$0$Method = var10000[0]; CGLIB$equals$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$0"); CGLIB$toString$1$Method = var10000[1]; CGLIB$toString$1$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$1"); CGLIB$hashCode$2$Method = var10000[2]; CGLIB$hashCode$2$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$2"); CGLIB$clone$3$Method = var10000[3]; CGLIB$clone$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$3"); var10000 = ReflectUtils.findMethods(new String[]{"info", "()V", "fly", "()V"}, (var1 = Class.forName("com.web.test.Human")).getDeclaredMethods()); CGLIB$info$4$Method = var10000[0]; CGLIB$info$4$Proxy = MethodProxy.create(var1, var0, "()V", "info", "CGLIB$info$4"); CGLIB$fly$5$Method = var10000[1]; CGLIB$fly$5$Proxy = MethodProxy.create(var1, var0, "()V", "fly", "CGLIB$fly$5"); } final boolean CGLIB$equals$0(Object var1) { return super.equals(var1); } public final boolean equals(Object var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if(var10000 != null) { Object var2 = var10000.intercept(this, CGLIB$equals$0$Method, new Object[]{var1}, CGLIB$equals$0$Proxy); return var2 == null?false:((Boolean)var2).booleanValue(); } else { return super.equals(var1); } } final String CGLIB$toString$1() { return super.toString(); } public final String toString() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null?(String)var10000.intercept(this, CGLIB$toString$1$Method, CGLIB$emptyArgs, CGLIB$toString$1$Proxy):super.toString(); } final int CGLIB$hashCode$2() { return super.hashCode(); } public final int hashCode() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if(var10000 != null) { Object var1 = var10000.intercept(this, CGLIB$hashCode$2$Method, CGLIB$emptyArgs, CGLIB$hashCode$2$Proxy); return var1 == null?0:((Number)var1).intValue(); } else { return super.hashCode(); } } final Object CGLIB$clone$3() throws CloneNotSupportedException { return super.clone(); } protected final Object clone() throws CloneNotSupportedException { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null?var10000.intercept(this, CGLIB$clone$3$Method, CGLIB$emptyArgs, CGLIB$clone$3$Proxy):super.clone(); } final void CGLIB$info$4() { super.info(); } public final void info() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if(var10000 != null) { var10000.intercept(this, CGLIB$info$4$Method, CGLIB$emptyArgs, CGLIB$info$4$Proxy); } else { super.info(); } } final void CGLIB$fly$5() { super.fly(); } public final void fly() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if(var10000 != null) { var10000.intercept(this, CGLIB$fly$5$Method, CGLIB$emptyArgs, CGLIB$fly$5$Proxy); } else { super.fly(); } } public static MethodProxy CGLIB$findMethodProxy(Signature var0) { String var10000 = var0.toString(); switch(var10000.hashCode()) { case -1271409118: if(var10000.equals("fly()V")) { return CGLIB$fly$5$Proxy; } break; case -508378822: if(var10000.equals("clone()Ljava/lang/Object;")) { return CGLIB$clone$3$Proxy; } break; case 1826985398: if(var10000.equals("equals(Ljava/lang/Object;)Z")) { return CGLIB$equals$0$Proxy; } break; case 1913648695: if(var10000.equals("toString()Ljava/lang/String;")) { return CGLIB$toString$1$Proxy; } break; case 1945358343: if(var10000.equals("info()V")) { return CGLIB$info$4$Proxy; } break; case 1984935277: if(var10000.equals("hashCode()I")) { return CGLIB$hashCode$2$Proxy; } } return null; } public Human$$EnhancerByCGLIB$$9fc9106() { CGLIB$BIND_CALLBACKS(this); } public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) { CGLIB$THREAD_CALLBACKS.set(var0); } public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) { CGLIB$STATIC_CALLBACKS = var0; } private static final void CGLIB$BIND_CALLBACKS(Object var0) { Human$$EnhancerByCGLIB$$9fc9106 var1 = (Human$$EnhancerByCGLIB$$9fc9106)var0; if(!var1.CGLIB$BOUND) { var1.CGLIB$BOUND = true; Object var10000 = CGLIB$THREAD_CALLBACKS.get(); if(var10000 == null) { var10000 = CGLIB$STATIC_CALLBACKS; if(CGLIB$STATIC_CALLBACKS == null) { return; } } var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0]; } } public Object newInstance(Callback[] var1) { CGLIB$SET_THREAD_CALLBACKS(var1); Human$$EnhancerByCGLIB$$9fc9106 var10000 = new Human$$EnhancerByCGLIB$$9fc9106(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Callback var1) { CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1}); Human$$EnhancerByCGLIB$$9fc9106 var10000 = new Human$$EnhancerByCGLIB$$9fc9106(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) { CGLIB$SET_THREAD_CALLBACKS(var3); Human$$EnhancerByCGLIB$$9fc9106 var10000 = new Human$$EnhancerByCGLIB$$9fc9106; switch(var1.length) { case 0: var10000.<init>(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; default: throw new IllegalArgumentException("Constructor not found"); } } public Callback getCallback(int var1) { CGLIB$BIND_CALLBACKS(this); MethodInterceptor var10000; switch(var1) { case 0: var10000 = this.CGLIB$CALLBACK_0; break; default: var10000 = null; } return var10000; } public void setCallback(int var1, Callback var2) { switch(var1) { case 0: this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2; default: } } public Callback[] getCallbacks() { CGLIB$BIND_CALLBACKS(this); return new Callback[]{this.CGLIB$CALLBACK_0}; } public void setCallbacks(Callback[] var1) { this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0]; } static { CGLIB$STATICHOOK1(); } }
对比和上面的 SuperMan$$EnhancerByCGLIB$$3be74240 发现并无差别(此时类中还无自定义方法)。
需要注意的是,这里只是测试绑定的代理目标对象为接口的可能性,代理类实现类接口的方法,并将方法的调用转发到intercept—具体业务逻辑实现。且在intercept中, obj = method.invoke(new SuperMan(), args); 将实际实现类写死了。
实际实现类(SuperMan)中添加自定义方法
如下,修改SuperMan:
// 被代理类 class SuperMan implements Human { public void info() { System.out.println("我是超人!我怕谁!"); } public void fly() { System.out.println("I believe I can fly!"); } public void self(){ System.out.println("this is suman's method--self !"); } }
测试代码如下–传入实现类对象:
import java.lang.reflect.Method; import net.sf.cglib.core.DebuggingClassWriter; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class TestCglibProxy { public static void main(String[] args) { //创建一个被代理类的对象 SuperMan man = new SuperMan(); String path = CGLibProxy.class.getResource(".").getPath(); System.out.println(path); System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path); CGLibProxy cgLibProxy = new CGLibProxy(); Object obj = cgLibProxy.getProxyInstance(man);//返回一个代理类的对象 System.out.println(obj.getClass()); //class com.web.test.SuperMan$$EnhancerByCGLIB$$3be74240 Suman su = (Suman)obj; su.info();//通过代理类的对象调用重写的抽象方法 System.out.println(); // 注意,这里调用Suman自定义方法 su.self(); } } class CGLibProxy implements MethodInterceptor { private Object targetObject;// CGLib需要代理的目标对象 public Object getProxyInstance(Object obj) { this.targetObject = obj; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(obj.getClass()); enhancer.setCallback(this); Object proxyObj = enhancer.create(); return proxyObj;// 返回代理对象 } public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object obj = null; //模拟功能增强 HumanUtil humanUtil = new HumanUtil(); humanUtil.method1(); // 执行目标目标对象方法 obj = method.invoke(targetObject, args); //模拟功能增强 humanUtil.method2(); return obj; } }
测试结果如下图:
毫无疑问是可以的,因为代理类继承自目标被代理类,故而添加的自定义方法可以被实现。因为CGLIB是继承自目标类-SuperMan,而非实现目标类的上层接口-Human!
此时生成的 SuperMan$$EnhancerByCGLIB$$3be74240.class 源码如下:
//... 省略代码,这里只表明方法 final void CGLIB$info$0() { super.info(); } public final void info() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if(var10000 != null) { var10000.intercept(this, CGLIB$info$0$Method, CGLIB$emptyArgs, CGLIB$info$0$Proxy); } else { super.info(); } } final void CGLIB$fly$1() { super.fly(); } public final void fly() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if(var10000 != null) { var10000.intercept(this, CGLIB$fly$1$Method, CGLIB$emptyArgs, CGLIB$fly$1$Proxy); } else { super.fly(); } } final void CGLIB$self$2() { super.self(); } public final void self() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if(var10000 != null) { var10000.intercept(this, CGLIB$self$2$Method, CGLIB$emptyArgs, CGLIB$self$2$Proxy); } else { super.self(); } }
此时如果使用①中的代码–即 enhancer.setSuperclass(obj); 传入Human.class,intercept中方法反射调用执行Suman.self()是会抛异常的,且生成的代理类源码中无self方法!
测试代码如下:
public class TestCglibProxy2 { public static void main(String[] args) { String path = CGLibProxy.class.getResource(".").getPath(); System.out.println(path); System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path); CGLibProxy2 cgLibProxy = new CGLibProxy2(); //这里传入Human Object obj = cgLibProxy.getProxyInstance(Human.class);//返回一个代理类的对象 System.out.println(obj.getClass()); // 强转可能会抛异常 SuperMan su = (SuperMan)obj; su.info(); System.out.println(); // 尝试调用Suman私有方法 su.self(); } } class CGLibProxy2 implements MethodInterceptor { public Object getProxyInstance(Class<?> obj) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(obj); enhancer.setCallback(this); Object proxyObj = enhancer.create(); return proxyObj;// 返回代理对象 } public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object obj = null; //模拟功能增强 HumanUtil humanUtil = new HumanUtil(); humanUtil.method1(); // 执行目标目标对象方法 obj = method.invoke(new SuperMan(), args); //模拟功能增强 humanUtil.method2(); return obj; } }
测试结果如下:
生成的代理类 Human$$EnhancerByCGLIB$$9fc9106.class并无Suman.self()—很显然的事情!!!
Cglib动态代理总结
① CGlib可以传入接口也可以传入普通的类,接口使用实现的方式,普通类使用会使用继承的方式生成代理类。
通常使用Cglib的时候侧重于实际实现类!!
② 由于是继承方式,如果是 static方法,private方法,final方法是不能被代理的。
③ CGLIB会默认代理Object中equals,toString,hashCode,clone等方法。比JDK代理多了clone。
获取JDK/Cglib动态代理对象
至此可以获取动态代理的class 文件,那么如何在项目中获取动态代理的目标对象呢?
示例代码如下:
import java.lang.reflect.Field; import org.springframework.aop.framework.AdvisedSupport; import org.springframework.aop.framework.AopProxy; import org.springframework.aop.support.AopUtils; public class AopTargetUtils { /** * 获取 目标对象 * @param proxy 代理对象 * @return * @throws Exception */ public static Object getTarget(Object proxy) throws Exception { if(!AopUtils.isAopProxy(proxy)) { return proxy;//不是代理对象 } if(AopUtils.isJdkDynamicProxy(proxy)) { return getJdkDynamicProxyTargetObject(proxy); } else { //cglib return getCglibProxyTargetObject(proxy); } } private static Object getCglibProxyTargetObject(Object proxy) throws Exception { Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0"); h.setAccessible(true); Object dynamicAdvisedInterceptor = h.get(proxy); Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised"); advised.setAccessible(true); Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget(); return target; } private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception { Field h = proxy.getClass().getSuperclass().getDeclaredField("h"); h.setAccessible(true); AopProxy aopProxy = (AopProxy) h.get(proxy); Field advised = aopProxy.getClass().getDeclaredField("advised"); advised.setAccessible(true); Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget(); return target; } }
Spring中动态代理的实现
Spring代理实际上是对JDK代理和CGLIB代理做了一层封装,并且引入了AOP概念:Aspect、advice、joinpoint等等,同时引入了AspectJ中的一些注解@pointCut,@after,@before等等。Spring Aop严格的来说都是动态代理。
Spring在选择用JDK还是CGLiB的依据:
- 当Bean实现接口时,Spring就会用JDK的动态代理
- 当Bean没有实现接口时,Spring使用CGlib是实现
如何强制使用CGLIB实现AOP?
- 添加CGLIB库,SPRING_HOME/cglib/*.jar
- 可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)
到此这篇关于CGLIB代理的使用与原理解析的文章就介绍到这了,更多相关CGLIB代理原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Java中ByteArrayOutputStream乱码问题解决
本文主要介绍了Java中ByteArrayOutputStream乱码问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2023-07-07教你如何把Eclipse创建的Web项目(非Maven)导入Idea
这篇文章主要介绍了教你如何把Eclipse创建的Web项目(非Maven)导入Idea,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2021-04-04
最新评论