CGLIB代理使用与原理详解
相关博文
Java中动态代理使用与原理详解
Java中静态代理使用与原理详解
【1】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$$3be74240Human 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!
=======方法二=======
【2】获取代理类源码
有了源码才好分析验证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$$3be74240Human hu = (Human)obj;hu.info();//通过代理类的对象调用重写的抽象方法System.out.println();hu.fly();}
测试结果如下:
生成的代理类名字SuperMan$$EnhancerByCGLIB$$3be74240
,源码如下:
可以直接在http://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();}// 获取方法的 MethodProxypublic 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};}// 初始化定义的callbackpublic 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对象,参数列表等传入进去。
【3】两个小问题
如果代理的目标对象为接口行不行?·
接口中的方法代理类实现了,那么类中自定义的方法代理类是否也可以实现?
毫无疑问,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$$9fc9106Human hu = (Human)obj;hu.info();//通过代理类的对象调用重写的抽象方法System.out.println();hu.fly();}
}class CGLibProxy2 implements MethodInterceptor { public Object getProxyInstance(Class<?> obj) { Enhancer enhancer = new Enhancer(); // 这里传入Classenhancer.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$$3be74240Suman 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();//这里传入HumanObject 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。
【5】获取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; } }
【6】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代理使用与原理详解相关推荐
- 【Android架构师java原理详解】二;反射原理及动态代理模式
前言: 本篇为Android架构师java原理专题二:反射原理及动态代理模式 大公司面试都要求我们有扎实的Java语言基础.而很多Android开发朋友这一块并不是很熟练,甚至半路初级底子很薄,这给我 ...
- Spring事务原理详解
一.使用 spring事务开启和使用比较简单,需要有数据源和事务管理器,然后在启动门面类上开启事务,在需要使用事务的地方添加注解就可以了,我们简单做一下回顾. 1.配置数据源 spring.datas ...
- nginx配置文件及工作原理详解
nginx配置文件及工作原理详解 1 nginx配置文件的结构 2 nginx工作原理 1 nginx配置文件的结构 1)以下是nginx配置文件默认的主要内容: #user nobody; #配置用 ...
- 深入剖析Redis系列(三) - Redis集群模式搭建与原理详解
前言 在 Redis 3.0 之前,使用 哨兵(sentinel)机制来监控各个节点之间的状态.Redis Cluster 是 Redis 的 分布式解决方案,在 3.0 版本正式推出,有效地解决了 ...
- SVM分类器原理详解
SVM分类器原理详解 标签: svm文本分类java 2015-08-21 11:51 2399人阅读 评论(0) 收藏 举报 分类: 数据挖掘 文本处理(16) 机器学习 分类算法(10) 目 ...
- ASP.NET页面与IIS底层交互和工作原理详解(一)
第一回: 引言 我查阅过不少Asp.Net的书籍,发现大多数作者都是站在一个比较高的层次上讲解Asp.Net.他们耐心.细致地告诉你如何一步步拖放控件.设置控件属性.编写CodeBehind代码,以实 ...
- mybatis的原理详解
mybatis的原理详解 原理图 执行的原理图如下图所示: 配置文件分析 config.xml: <?xml version="1.0" encoding="UTF ...
- 计算机网络知识详解之:TCP连接原理详解
网络知识详解之:TCP连接原理详解 计算机网络相关知识体系详解 网络知识详解之:TCP连接原理详解 网络知识详解之:HTTP协议基础 网络知识详解之:HTTPS通信原理剖析(对称.非对称加密.数字签名 ...
- 【胖虎的逆向之路】02——Android整体加壳原理详解实现
[胖虎的逆向之路](02)--Android整体加壳原理详解&实现 Android Apk的加壳原理流程及详解 文章目录 [胖虎的逆向之路](02)--Android整体加壳原理详解& ...
- proxytable代理不生效_proxyTable代理跨域使用详解
这次给大家带来proxyTable代理跨域使用详解,proxyTable代理跨域使用的注意事项有哪些,下面就是实战案例,一起来看一下. 什么是代理跨域 浏览器之间有同源策略,出于安全考虑不同域之间不允 ...
最新文章
- 面试造飞机系列:面对Redis持久化连环Call,你还顶得住吗?
- C++面向对象基础(二)
- Bug只让变量生效一次的思路
- react部署在node_如何在没有命令行的情况下在3分钟内将React + Node应用程序部署到Heroku
- 计算机网络——零碎知识点
- 多项式的链式存储方案
- python dataframe中缺失值处理
- 树莓派 Learning 001 装机 ---之 1 安装NOOBS系统
- 安装i3_330mm长显卡,240水冷,我的第一款小钢炮,雷匠R-i3装机体验
- dsoframer java_(二) 内嵌WORD/OFFICE的WINFORM程序——DSOFRAMER使用小结
- window 下 win10 jdk8安装与环境变量的配置(超级详细)
- 通信系列2: 深入浅出SIP协议
- Ubuntu 16.04 修改Home目录下的 中文目录 为英文目录
- Request Headers请求头和Response Headers响应头,有啥区别呢?
- win10无线信号强度测试软件,WinFi Lite(WIFI分析工具) V1.0.15.0 官方版
- Excel重复行删除
- 【Win10微信截图】Win10的wechat截图模糊修正
- cad指北针lisp_CAD指北针
- 创建新的maven项目时报错找不到插件:Cannot resolve plugin org.apache.maven.plugins:maven-compiler-plugin:3.1
- 涉及计算机控制的课题,长春理工大学电子教案-计算机控制系统 第1章 绪论
热门文章
- PaysApi第三方支付接口的接入与使用 React前端SSM后端
- STM32驱动SPI LCD屏幕
- 锂电池UN38.3测试项目介绍
- 2019年中国锂电池产业竞争格局
- mf4350d驱动下载linux,佳能 imageCLASS MF4350d 驱动程序下载-更新佳能软件(打印机)
- 数学建模作图准备(Python-Matplotlib)Matplotlib
- 迷你迅雷(官方版)不含广告,不用会员,多线程急速
- OverFeat 个人总结
- 微信支付接口 java服务器,JAVA微信支付接口开发——支付(示例代码)
- 监督学习、无监督学习、弱监督学习、半监督学习、强化学习概念