CGLIB代理的使用與原理解析
CGLIB概述
Cglib代理
靜態(tài)代理和JDK 代理模式都要求目標(biāo)對象是實現(xiàn)一個接口,但是有時候目標(biāo)對象只是一個單獨的對象,并沒有實現(xiàn)任何的接口,這個時候可使用目標(biāo)對象子類來實現(xiàn)代理-這就是Cglib 代理。
JDK中提供的生成動態(tài)代理類的機制有個鮮明的特點是:
- 某個類必須有實現(xiàn)的接口
- 生成的代理類也只能代理某個類接口定義的方法。
那么如果一個類沒有實現(xiàn)接口怎么辦呢?
這就有CGLIB的誕生了,前面說的JDK的動態(tài)代理的實現(xiàn)方式是實現(xiàn)相關(guān)的接口成為接口的實現(xiàn)類,那么我們自然可以想到用繼承的方式實現(xiàn)相關(guān)的代理類。
Cglib 代理也叫作子類代理,它是在內(nèi)存中構(gòu)建一個子類對象從而實現(xiàn)對目標(biāo)對象功能擴展, 有些書也將Cglib 代理歸屬到動態(tài)代理。
CGLIB是針對類實現(xiàn)代理,主要是對指定的類生成一個子類,覆蓋其中的方法。因為是繼承,所以該類或方法最好不要聲明成final, static方法,private方法,final方法是不能被代理的
Cglib 是一個強大的高性能的代碼生成包,它可以在運行期擴展java 類與實現(xiàn)java 接口.它廣泛的被許多AOP 的框架使用,例如Spring AOP,實現(xiàn)方法攔截。
在AOP 編程中如何選擇代理模式:
- 目標(biāo)對象需要實現(xiàn)接口,用JDK 代理
- 目標(biāo)對象不需要實現(xiàn)接口,用Cglib 代理
Cglib 包的底層是通過使用字節(jié)碼處理框架ASM 來轉(zhuǎn)換字節(jié)碼并生成新的類
應(yīng)用案例
pom依賴
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>在JDK動態(tài)代理的代碼基礎(chǔ)上進(jìn)行修改
① 測試客戶端
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) {
//創(chuàng)建一個被代理類的對象
SuperMan man = new SuperMan();
CGLibProxy cgLibProxy = new CGLibProxy();
//返回一個代理類的對象--注意這里現(xiàn)在傳入的是實現(xiàn)類
Object obj = cgLibProxy.getProxyInstance(man);
System.out.println(obj.getClass());
//class com.web.test.SuperMan$$EnhancerByCGLIB$$3be74240
Human hu = (Human)obj;
//通過代理類的對象調(diào)用重寫的抽象方法
hu.info();
System.out.println();
hu.fly();
}
}② 自定義CGLibProxy
class CGLibProxy implements MethodInterceptor {
// CGLib需要代理的目標(biāo)對象
private Object targetObject;
public Object getProxyInstance(Object obj) {
this.targetObject = obj;
//1. 創(chuàng)建一個工具類
Enhancer enhancer = new Enhancer();
// 2.設(shè)置父類--可以是類或者接口
enhancer.setSuperclass(obj.getClass());
//3. 設(shè)置回調(diào)函數(shù)
enhancer.setCallback(this);
//4. 創(chuàng)建子類對象,即代理對象
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();
// 執(zhí)行目標(biāo)目標(biāo)對象方法
obj = method.invoke(targetObject, args);
//模擬功能增強
humanUtil.method2();
return obj;
}
}HumanUtil 如下:
class HumanUtil {
public void method1() {
System.out.println("=======方法一=======");
}
public void method2() {
System.out.println("=======方法二=======");
}
}測試結(jié)果
如下所示:
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();//創(chuàng)建一個被代理類的對象
// 添加如下代碼,獲取代理類源文件
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();//通過代理類的對象調(diào)用重寫的抽象方法
System.out.println();
hu.fly();
}測試結(jié)果如下:

生成的代理類名字 SuperMan$$EnhancerByCGLIB$$3be74240 ,源碼如下:
可以直接在//javare.cn/網(wǎng)站下在線反編譯。
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;
//繼承目標(biāo)被代理類
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;
// 一系列私有靜態(tài)常量定義
// 常量初始化
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的方法會額外實現(xiàn)一個和原方法一模一樣的方法
final void CGLIB$info$0() {
super.info();
}
// 代理對象的方法調(diào)用將會轉(zhuǎn)發(fā)到代理對象的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;
}
//無參構(gòu)造器
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];
}
// 這里,類加載的時候首先執(zhí)行?。?!
static {
CGLIB$STATICHOOK1();
}
}可以發(fā)現(xiàn)這個類繼承自接口實現(xiàn)類–SuperMan,其在加載的時候會先進(jìn)行一系列靜態(tài)常量的初始化且在實例化的時候調(diào)用 CGLIB$BIND_CALLBACKS(this); 進(jìn)行call back的綁定。
那么現(xiàn)在的情況就是我們的生成了一個代理類,這個代理類是我們需要代理的實現(xiàn)類的繼承類。我們的被代理類的方法在這個代理類中幫我們重寫了,并且全部變成了final的。同時覆蓋了一些Object類中的方法。
以 info 這個方法舉例,方法中會調(diào)用 MethodInterceptor 類中的 intercept 方法(也就是我們實現(xiàn)的邏輯的地方),同時把自己的Method對象,參數(shù)列表等傳入進(jìn)去。
兩個小問題
如果代理的目標(biāo)對象為接口行不行?·
接口中的方法代理類實現(xiàn)了,那么類中自定義的方法代理類是否也可以實現(xiàn)?
毫無疑問,cglib是基于類的動態(tài)代理,代理類繼承自目標(biāo)類, 類中的方法除了final自然可以繼承 !
傳入接口為代理對象進(jìn)行測試
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();//通過代理類的對象調(diào)用重寫的抽象方法
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();
// 執(zhí)行目標(biāo)目標(biāo)對象方法--這里直接傳入目標(biāo)對象
obj = method.invoke(new SuperMan(), args);
//模擬功能增強
humanUtil.method2();
return obj;
}
}測試結(jié)果如下圖:

此時生成的源碼 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;
//注意,這里變?yōu)榱藢崿F(xiàn)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 發(fā)現(xiàn)并無差別(此時類中還無自定義方法)。
需要注意的是,這里只是測試綁定的代理目標(biāo)對象為接口的可能性,代理類實現(xiàn)類接口的方法,并將方法的調(diào)用轉(zhuǎn)發(fā)到intercept—具體業(yè)務(wù)邏輯實現(xiàn)。且在intercept中, obj = method.invoke(new SuperMan(), args); 將實際實現(xiàn)類寫死了。
實際實現(xiàn)類(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 !");
}
}測試代碼如下–傳入實現(xiàn)類對象:
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) {
//創(chuàng)建一個被代理類的對象
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();//通過代理類的對象調(diào)用重寫的抽象方法
System.out.println();
// 注意,這里調(diào)用Suman自定義方法
su.self();
}
}
class CGLibProxy implements MethodInterceptor {
private Object targetObject;// CGLib需要代理的目標(biāo)對象
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();
// 執(zhí)行目標(biāo)目標(biāo)對象方法
obj = method.invoke(targetObject, args);
//模擬功能增強
humanUtil.method2();
return obj;
}
}測試結(jié)果如下圖:

毫無疑問是可以的,因為代理類繼承自目標(biāo)被代理類,故而添加的自定義方法可以被實現(xiàn)。因為CGLIB是繼承自目標(biāo)類-SuperMan,而非實現(xiàn)目標(biāo)類的上層接口-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中方法反射調(diào)用執(zhí)行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());
// 強轉(zhuǎn)可能會拋異常
SuperMan su = (SuperMan)obj;
su.info();
System.out.println();
// 嘗試調(diào)用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();
// 執(zhí)行目標(biāo)目標(biāo)對象方法
obj = method.invoke(new SuperMan(), args);
//模擬功能增強
humanUtil.method2();
return obj;
}
}測試結(jié)果如下:

生成的代理類 Human$$EnhancerByCGLIB$$9fc9106.class并無Suman.self()—很顯然的事情!??!
Cglib動態(tài)代理總結(jié)
① CGlib可以傳入接口也可以傳入普通的類,接口使用實現(xiàn)的方式,普通類使用會使用繼承的方式生成代理類。
通常使用Cglib的時候側(cè)重于實際實現(xiàn)類?。?/p>
② 由于是繼承方式,如果是 static方法,private方法,final方法是不能被代理的。
③ CGLIB會默認(rèn)代理Object中equals,toString,hashCode,clone等方法。比JDK代理多了clone。
獲取JDK/Cglib動態(tài)代理對象
至此可以獲取動態(tài)代理的class 文件,那么如何在項目中獲取動態(tài)代理的目標(biāo)對象呢?
示例代碼如下:
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 {
/**
* 獲取 目標(biāo)對象
* @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中動態(tài)代理的實現(xiàn)
Spring代理實際上是對JDK代理和CGLIB代理做了一層封裝,并且引入了AOP概念:Aspect、advice、joinpoint等等,同時引入了AspectJ中的一些注解@pointCut,@after,@before等等。Spring Aop嚴(yán)格的來說都是動態(tài)代理。
Spring在選擇用JDK還是CGLiB的依據(jù):
- 當(dāng)Bean實現(xiàn)接口時,Spring就會用JDK的動態(tài)代理
- 當(dāng)Bean沒有實現(xiàn)接口時,Spring使用CGlib是實現(xiàn)
如何強制使用CGLIB實現(xiàn)AOP?
- 添加CGLIB庫,SPRING_HOME/cglib/*.jar
- 可以強制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)
到此這篇關(guān)于CGLIB代理的使用與原理解析的文章就介紹到這了,更多相關(guān)CGLIB代理原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Cloud Admin健康檢查 郵件、釘釘群通知的實現(xiàn)
這篇文章主要介紹了Spring Cloud Admin健康檢查 郵件、釘釘群通知的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
springmvc項目使用@Valid+BindingResult遇到的問題
這篇文章主要介紹了springmvc項目使用@Valid+BindingResult遇到的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
vue 使用vuex在頁面跳轉(zhuǎn)的實現(xiàn)方式
這篇文章主要介紹了vue 使用vuex在頁面跳轉(zhuǎn)的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08
Spring?Boot?使用?Disruptor?做內(nèi)部高性能消息隊列
這篇文章主要介紹了Spring?Boot?使用?Disruptor?做內(nèi)部高性能消息隊列,工作中遇到項目使用Disruptor做消息隊列,對你沒看錯,不是Kafka,也不是rabbitmq。Disruptor有個最大的優(yōu)點就是快,還有一點它是開源的哦,下面做個簡單的記錄2022-06-06

