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

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

此時(shí)生成的源碼 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)榱藢?shí)現(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();
}
}對(duì)比和上面的 SuperMan$$EnhancerByCGLIB$$3be74240 發(fā)現(xiàn)并無(wú)差別(此時(shí)類(lèi)中還無(wú)自定義方法)。
需要注意的是,這里只是測(cè)試綁定的代理目標(biāo)對(duì)象為接口的可能性,代理類(lèi)實(shí)現(xiàn)類(lèi)接口的方法,并將方法的調(diào)用轉(zhuǎn)發(fā)到intercept—具體業(yè)務(wù)邏輯實(shí)現(xiàn)。且在intercept中, obj = method.invoke(new SuperMan(), args); 將實(shí)際實(shí)現(xiàn)類(lèi)寫(xiě)死了。
實(shí)際實(shí)現(xiàn)類(lèi)(SuperMan)中添加自定義方法
如下,修改SuperMan:
// 被代理類(lèi)
class SuperMan implements Human {
public void info() {
System.out.println("我是超人!我怕誰(shuí)!");
}
public void fly() {
System.out.println("I believe I can fly!");
}
public void self(){
System.out.println("this is suman's method--self !");
}
}測(cè)試代碼如下–傳入實(shí)現(xiàn)類(lèi)對(duì)象:
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)建一個(gè)被代理類(lèi)的對(duì)象
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);//返回一個(gè)代理類(lèi)的對(duì)象
System.out.println(obj.getClass());
//class com.web.test.SuperMan$$EnhancerByCGLIB$$3be74240
Suman su = (Suman)obj;
su.info();//通過(guò)代理類(lèi)的對(duì)象調(diào)用重寫(xiě)的抽象方法
System.out.println();
// 注意,這里調(diào)用Suman自定義方法
su.self();
}
}
class CGLibProxy implements MethodInterceptor {
private Object targetObject;// CGLib需要代理的目標(biāo)對(duì)象
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;// 返回代理對(duì)象
}
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
Object obj = null;
//模擬功能增強(qiáng)
HumanUtil humanUtil = new HumanUtil();
humanUtil.method1();
// 執(zhí)行目標(biāo)目標(biāo)對(duì)象方法
obj = method.invoke(targetObject, args);
//模擬功能增強(qiáng)
humanUtil.method2();
return obj;
}
}測(cè)試結(jié)果如下圖:

毫無(wú)疑問(wèn)是可以的,因?yàn)榇眍?lèi)繼承自目標(biāo)被代理類(lèi),故而添加的自定義方法可以被實(shí)現(xiàn)。因?yàn)镃GLIB是繼承自目標(biāo)類(lèi)-SuperMan,而非實(shí)現(xiàn)目標(biāo)類(lèi)的上層接口-Human!
此時(shí)生成的 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();
}
}此時(shí)如果使用①中的代碼–即 enhancer.setSuperclass(obj); 傳入Human.class,intercept中方法反射調(diào)用執(zhí)行Suman.self()是會(huì)拋異常的,且生成的代理類(lèi)源碼中無(wú)self方法!
測(cè)試代碼如下:
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);//返回一個(gè)代理類(lèi)的對(duì)象
System.out.println(obj.getClass());
// 強(qiáng)轉(zhuǎn)可能會(huì)拋異常
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;// 返回代理對(duì)象
}
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
Object obj = null;
//模擬功能增強(qiáng)
HumanUtil humanUtil = new HumanUtil();
humanUtil.method1();
// 執(zhí)行目標(biāo)目標(biāo)對(duì)象方法
obj = method.invoke(new SuperMan(), args);
//模擬功能增強(qiáng)
humanUtil.method2();
return obj;
}
}測(cè)試結(jié)果如下:

生成的代理類(lèi) Human$$EnhancerByCGLIB$$9fc9106.class并無(wú)Suman.self()—很顯然的事情?。?!
Cglib動(dòng)態(tài)代理總結(jié)
① CGlib可以傳入接口也可以傳入普通的類(lèi),接口使用實(shí)現(xiàn)的方式,普通類(lèi)使用會(huì)使用繼承的方式生成代理類(lèi)。
通常使用Cglib的時(shí)候側(cè)重于實(shí)際實(shí)現(xiàn)類(lèi)??!
② 由于是繼承方式,如果是 static方法,private方法,final方法是不能被代理的。
③ CGLIB會(huì)默認(rèn)代理Object中equals,toString,hashCode,clone等方法。比JDK代理多了clone。
獲取JDK/Cglib動(dòng)態(tài)代理對(duì)象
至此可以獲取動(dòng)態(tài)代理的class 文件,那么如何在項(xiàng)目中獲取動(dòng)態(tài)代理的目標(biāo)對(duì)象呢?
示例代碼如下:
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)對(duì)象
* @param proxy 代理對(duì)象
* @return
* @throws Exception
*/
public static Object getTarget(Object proxy) throws Exception {
if(!AopUtils.isAopProxy(proxy)) {
return proxy;//不是代理對(duì)象
}
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中動(dòng)態(tài)代理的實(shí)現(xiàn)
Spring代理實(shí)際上是對(duì)JDK代理和CGLIB代理做了一層封裝,并且引入了AOP概念:Aspect、advice、joinpoint等等,同時(shí)引入了AspectJ中的一些注解@pointCut,@after,@before等等。Spring Aop嚴(yán)格的來(lái)說(shuō)都是動(dòng)態(tài)代理。
Spring在選擇用JDK還是CGLiB的依據(jù):
- 當(dāng)Bean實(shí)現(xiàn)接口時(shí),Spring就會(huì)用JDK的動(dòng)態(tài)代理
- 當(dāng)Bean沒(méi)有實(shí)現(xiàn)接口時(shí),Spring使用CGlib是實(shí)現(xiàn)
如何強(qiáng)制使用CGLIB實(shí)現(xiàn)AOP?
- 添加CGLIB庫(kù),SPRING_HOME/cglib/*.jar
- 可以強(qiáng)制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)
到此這篇關(guān)于CGLIB代理的使用與原理解析的文章就介紹到這了,更多相關(guān)CGLIB代理原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java中的cglib代理詳解
- Java中Cglib代理和JDK代理的區(qū)別詳解
- 一文搞懂Java常見(jiàn)的三種代理模式(靜態(tài)代理、動(dòng)態(tài)代理和cglib代理)
- Spring之AOP兩種代理機(jī)制對(duì)比分析(JDK和CGLib動(dòng)態(tài)代理)
- 基于jdk動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理實(shí)現(xiàn)及區(qū)別說(shuō)明
- Java JDK與cglib動(dòng)態(tài)代理有什么區(qū)別
- 解析動(dòng)態(tài)代理jdk的Proxy與spring的CGlib(包括區(qū)別介紹)
相關(guān)文章
Java使用Kaptcha實(shí)現(xiàn)簡(jiǎn)單的驗(yàn)證碼生成器
這篇文章主要為大家詳細(xì)介紹了Java如何使用Kaptcha實(shí)現(xiàn)簡(jiǎn)單的驗(yàn)證碼生成器,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考下2024-02-02
Windows上安裝并使用SDKMAN詳細(xì)教程(JDK多版本管理)
在Linux和macOS上,開(kāi)發(fā)者可以輕松使用SDKMAN來(lái)管理多個(gè)JDK版本,但Windows原生并不直接支持SDKMAN,這篇文章主要介紹了Windows上安裝并使用SDKMAN管理JDK多版本管理的相關(guān)資料,需要的朋友可以參考下2026-05-05
Java?基于Hutool實(shí)現(xiàn)DES加解密示例詳解
這篇文章主要介紹了Java基于Hutool實(shí)現(xiàn)DES加解密,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08
IDEA2024創(chuàng)建Web項(xiàng)目以及配置Tomcat的實(shí)現(xiàn)步驟
在Web項(xiàng)目的開(kāi)發(fā)過(guò)程中,Tomcat作為一款開(kāi)源的Servlet容器,扮演著至關(guān)重要的角色,本文將詳細(xì)闡述2024版本的idea配置Tomcat的全過(guò)程,下面就來(lái)詳細(xì)的介紹一下2025-10-10
spring?boot只需兩步優(yōu)雅整合activiti示例解析
這篇文章主要主要來(lái)教大家spring?boot優(yōu)雅整合activiti只需兩步就可完成測(cè)操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進(jìn)步2022-03-03
使用jaxp進(jìn)行dom解析_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了使用jaxp進(jìn)行dom解析的相關(guān)資料,需要的朋友可以參考下2017-08-08
JAVA基于SnakeYAML實(shí)現(xiàn)解析與序列化YAML
這篇文章主要介紹了JAVA基于SnakeYAML實(shí)現(xiàn)解析與序列化YAML,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
SpringBoot設(shè)置接口超時(shí)時(shí)間的方法
這篇文章主要介紹了SpringBoot設(shè)置接口超時(shí)時(shí)間的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08

