Java中的cglib原理解析
cglib原理解析
先放上示例代碼:
//Person.java
public class Person {
public void sayHello() {
System.out.println("Hello!");
}
}
//Test.java
import org.objectweb.asm.ClassWriter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.io.FileOutputStream;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Person.class);
//設(shè)置生成的類不繼承Factory接口
enhancer.setUseFactory(false);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Intercept!");
methodProxy.invokeSuper(o, objects);
return null;
}
});
Person person = (Person) enhancer.create();
person.sayHello();
//以下代碼是為了輸出cglib生成的類的class文件
ClassWriter cw = new ClassWriter(0);
enhancer.generateClass(cw);
byte[] klass = cw.toByteArray();
FileOutputStream fileOutputStream = new FileOutputStream(person.getClass().getName()+".class");
fileOutputStream.write(klass);
fileOutputStream.close();
}
}使用cglib生成代碼的過程很簡(jiǎn)單:
- new 一個(gè)Enhancer對(duì)象
- 調(diào)用它的setSuperclass()方法設(shè)置需要代理的類
- 調(diào)用它的setCallback()方法設(shè)置攔截被代理類方法時(shí)的邏輯
為了簡(jiǎn)單起見,我們還調(diào)用了setUseFactory(false)方法,使得生成的代理類不實(shí)現(xiàn)Factory接口(該接口提供了一些生成新對(duì)象的和設(shè)置對(duì)象的Callback的方法)。并且沒有使用CallbackFilter。
cglib生成對(duì)象時(shí)主要的邏輯在Enchancer類的generateClass方法里面:
public void generateClass(ClassVisitor v) throws Exception {
Class sc = (superclass == null) ? Object.class : superclass;
//如果被代理類是final類型的,拋出異常
if (TypeUtils.isFinal(sc.getModifiers()))
throw new IllegalArgumentException("Cannot subclass final class " + sc.getName());
//以下兩行代碼獲得被代理類的非私有構(gòu)造函數(shù)
List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors()));
filterConstructors(sc, constructors);
// Order is very important: must add superclass, then
// its superclass chain, then each interface and
// its superinterfaces.
List actualMethods = new ArrayList();
List interfaceMethods = new ArrayList();
final Set forcePublic = new HashSet();
//得到被代理類及其父類、接口的非final、非static、非private方法。這些方法是需要代理的(在不考慮CallbackFilter的情況下)
getMethods(sc, interfaces, actualMethods, interfaceMethods, forcePublic);
//獲得需要代理的方法的方法信息
List methods = CollectionUtils.transform(actualMethods, new Transformer() {
public Object transform(Object value) {
Method method = (Method)value;
int modifiers = Constants.ACC_FINAL
| (method.getModifiers()
& ~Constants.ACC_ABSTRACT
& ~Constants.ACC_NATIVE
& ~Constants.ACC_SYNCHRONIZED);
if (forcePublic.contains(MethodWrapper.create(method))) {
modifiers = (modifiers & ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC;
}
return ReflectUtils.getMethodInfo(method, modifiers);
}
});
ClassEmitter e = new ClassEmitter(v);
if (currentData == null) {
//生成class文件的版本號(hào)、類的訪問描述符、類名、父類名、接口,并生成SourceFile屬性
e.begin_class(Constants.V1_2,
Constants.ACC_PUBLIC,
getClassName(),
Type.getType(sc),
(useFactory ?
TypeUtils.add(TypeUtils.getTypes(interfaces), FACTORY) :
TypeUtils.getTypes(interfaces)),
Constants.SOURCE_FILE);
} else {
e.begin_class(Constants.V1_2,
Constants.ACC_PUBLIC,
getClassName(),
null,
new Type[]{FACTORY},
Constants.SOURCE_FILE);
}
List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance());
//以下生成代理類的字段,可以對(duì)照下面的反編譯結(jié)果觀看
//生成private boolean CGLIB$BOUND字段
e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null);
//生成public static Object CGLIB$FACTORY_DATA字段
e.declare_field(Constants.ACC_PUBLIC | Constants.ACC_STATIC, FACTORY_DATA_FIELD, OBJECT_TYPE, null);
if (!interceptDuringConstruction) {
e.declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null);
}
//生成private static final ThreadLocal CGLIB$THREAD_CALLBACKS字段
e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null);
//生成private static final Callback[] CGLIB$STATIC_CALLBACKS字段
e.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null);
if (serialVersionUID != null) {
e.declare_field(Constants.PRIVATE_FINAL_STATIC, Constants.SUID_FIELD_NAME, Type.LONG_TYPE, serialVersionUID);
}
//以下是生成Callback字段,可以看到,對(duì)應(yīng)每個(gè)設(shè)置的Callback,都會(huì)在代理類中生成一個(gè)對(duì)應(yīng)具體類型的字段
for (int i = 0; i < callbackTypes.length; i++) {
//在本例中生成的是private MethodInterceptor CGLIB$CALLBACK_0字段,后綴_0代表是在Enhancer中設(shè)置的第0個(gè)Callback
e.declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackTypes[i], null);
}
// This is declared private to avoid "public field" pollution
//生成private static Object CGLIB$CALLBACK_FILTER字段。如果Enhancer只設(shè)置了一個(gè)Callback并且沒有設(shè)置CallbackFilter,那么會(huì)默認(rèn)對(duì)該Enhancer對(duì)象添加一個(gè)指向第0個(gè)Callback的CallbackFilter
e.declare_field(Constants.ACC_PRIVATE | Constants.ACC_STATIC, CALLBACK_FILTER_FIELD, OBJECT_TYPE, null);
if (currentData == null) {
//這個(gè)函數(shù)生成需要代理類的方法
emitMethods(e, methods, actualMethods);
//生成構(gòu)造函數(shù)
emitConstructors(e, constructorInfo);
} else {
emitDefaultConstructor(e);
}
//以下三行代碼分別生成代理類的CGLIB$SET_THREAD_CALLBACKS、CGLIB$SET_STATIC_CALLBACKS和CGLIB$BIND_CALLBACKS函數(shù)
emitSetThreadCallbacks(e);
emitSetStaticCallbacks(e);
emitBindCallbacks(e);
if (useFactory || currentData != null) {
int[] keys = getCallbackKeys();
//如果useFactory為true就會(huì)生成幾個(gè)newInstance方法,還有幾個(gè)操作代理類的Callback的方法
emitNewInstanceCallbacks(e);
emitNewInstanceCallback(e);
emitNewInstanceMultiarg(e, constructorInfo);
emitGetCallback(e, keys);
emitSetCallback(e, keys);
emitGetCallbacks(e);
emitSetCallbacks(e);
}
e.end_class();
}使用Bytecode Viewer的CFR反編譯生成的代理類如下:
/*
* Decompiled with CFR 0_125.
*
* Could not load the following classes:
* Person
* Person$$EnhancerByCGLIB$$34b905e4
* net.sf.cglib.core.ReflectUtils
* net.sf.cglib.core.Signature
* net.sf.cglib.proxy.Callback
* net.sf.cglib.proxy.MethodInterceptor
* net.sf.cglib.proxy.MethodProxy
*/
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.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/*
* Exception performing whole class analysis ignored.
*/
public class Person$$EnhancerByCGLIB$$34b905e4
extends Person {
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$sayHello$0$Method;
private static final MethodProxy CGLIB$sayHello$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy;
static void CGLIB$STATICHOOK2() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class class_ = Class.forName("Person$$EnhancerByCGLIB$$34b905e4");
Class class_2 = Class.forName("java.lang.Object");
Method[] arrmethod = ReflectUtils.findMethods((String[])new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (Method[])class_2.getDeclaredMethods());
CGLIB$equals$1$Method = arrmethod[0];
CGLIB$equals$1$Proxy = MethodProxy.create(class_2, class_, (String)"(Ljava/lang/Object;)Z", (String)"equals", (String)"CGLIB$equals$1");
CGLIB$toString$2$Method = arrmethod[1];
CGLIB$toString$2$Proxy = MethodProxy.create(class_2, class_, (String)"()Ljava/lang/String;", (String)"toString", (String)"CGLIB$toString$2");
CGLIB$hashCode$3$Method = arrmethod[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(class_2, class_, (String)"()I", (String)"hashCode", (String)"CGLIB$hashCode$3");
CGLIB$clone$4$Method = arrmethod[3];
CGLIB$clone$4$Proxy = MethodProxy.create(class_2, class_, (String)"()Ljava/lang/Object;", (String)"clone", (String)"CGLIB$clone$4");
class_2 = Class.forName("Person");
CGLIB$sayHello$0$Method = ReflectUtils.findMethods((String[])new String[]{"sayHello", "()V"}, (Method[])class_2.getDeclaredMethods())[0];
CGLIB$sayHello$0$Proxy = MethodProxy.create(class_2, class_, (String)"()V", (String)"sayHello", (String)"CGLIB$sayHello$0");
}
final void CGLIB$sayHello$0() {
super.sayHello();
}
public final void sayHello() {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
Object object = methodInterceptor.intercept((Object)this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
return;
}
super.sayHello();
}
final boolean CGLIB$equals$1(Object object) {
return super.equals(object);
}
public final boolean equals(Object object) {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor == null) return super.equals(object);
Object object2 = methodInterceptor.intercept((Object)this, CGLIB$equals$1$Method, new Object[]{object}, CGLIB$equals$1$Proxy);
if (object2 == null) {
return false;
}
boolean bl = (Boolean)object2;
return bl;
}
final String CGLIB$toString$2() {
return super.toString();
}
public final String toString() {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor == null) return super.toString();
return (String)methodInterceptor.intercept((Object)this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy);
}
final int CGLIB$hashCode$3() {
return super.hashCode();
}
public final int hashCode() {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor == null) return super.hashCode();
Object object = methodInterceptor.intercept((Object)this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
if (object == null) {
return 0;
}
int n = ((Number)object).intValue();
return n;
}
final Object CGLIB$clone$4() throws CloneNotSupportedException {
return super.clone();
}
protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor == null) return super.clone();
return methodInterceptor.intercept((Object)this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy);
}
public static MethodProxy CGLIB$findMethodProxy(Signature signature) {
String string = signature.toString();
switch (string.hashCode()) {
case -508378822: {
if (!string.equals("clone()Ljava/lang/Object;")) return null;
return CGLIB$clone$4$Proxy;
}
case 1535311470: {
if (!string.equals("sayHello()V")) return null;
return CGLIB$sayHello$0$Proxy;
}
case 1826985398: {
if (!string.equals("equals(Ljava/lang/Object;)Z")) return null;
return CGLIB$equals$1$Proxy;
}
case 1913648695: {
if (!string.equals("toString()Ljava/lang/String;")) return null;
return CGLIB$toString$2$Proxy;
}
case 1984935277: {
if (!string.equals("hashCode()I")) return null;
return CGLIB$hashCode$3$Proxy;
}
}
return null;
}
public Person$$EnhancerByCGLIB$$34b905e4() {
Person$$EnhancerByCGLIB$$34b905e4 person$$EnhancerByCGLIB$$34b905e4 = this;
Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)person$$EnhancerByCGLIB$$34b905e4);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] arrcallback) {
CGLIB$THREAD_CALLBACKS.set(arrcallback);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] arrcallback) {
CGLIB$STATIC_CALLBACKS = arrcallback;
}
private static final void CGLIB$BIND_CALLBACKS(Object object) {
Person$$EnhancerByCGLIB$$34b905e4 person$$EnhancerByCGLIB$$34b905e4 = (Person$$EnhancerByCGLIB$$34b905e4)object;
if (person$$EnhancerByCGLIB$$34b905e4.CGLIB$BOUND) return;
person$$EnhancerByCGLIB$$34b905e4.CGLIB$BOUND = true;
Object t = CGLIB$THREAD_CALLBACKS.get();
if (t == null && (v783 = CGLIB$STATIC_CALLBACKS) == null) {
return;
}
person$$EnhancerByCGLIB$$34b905e4.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])t)[0];
}
static {
Person$$EnhancerByCGLIB$$34b905e4.CGLIB$STATICHOOK2();
}
}可以看到,在創(chuàng)建一個(gè)代理類的對(duì)象的時(shí)候,會(huì)先加載這個(gè)類,也就調(diào)用了類的靜態(tài)方法CGLIB$STATICHOOK2(),在這個(gè)函數(shù)中對(duì)類的其它靜態(tài)字段進(jìn)行了初始化,比如對(duì)應(yīng)每個(gè)需要代理的方法都生成兩個(gè)字段,一個(gè)是用于反射的Method對(duì)象,另一個(gè)是用于加快方法調(diào)用、避免反射帶來的開銷的MethodProxy對(duì)象。然后在構(gòu)造函數(shù)里面調(diào)用了CGLIB$BIND_CALLBACKS(this),在CGLIB$BIND_CALLBACKS方法中會(huì)把private MethodInterceptor CGLIB$CALLBACK_0字段和設(shè)置的靜態(tài)變量ThreadLocal CGLIB$THREAD_CALLBACKS進(jìn)行綁定,也就是說,設(shè)置的Callback并不是硬編碼在生成的代理類里面的,而是可以動(dòng)態(tài)地設(shè)置。
由于代理類繼承了被代理類,所以調(diào)用sayHello()方法時(shí)會(huì)直接調(diào)用代理類的sayHello()方法,而在代理類的方法中,調(diào)用了Callback的邏輯。
到此這篇關(guān)于Java中的cglib原理解析的文章就介紹到這了,更多相關(guān)cglib原理解析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring根據(jù)XML配置文件 p名稱空間注入屬性的實(shí)例
下面小編就為大家分享一篇Spring根據(jù)XML配置文件 p名稱空間注入屬性的實(shí)例,具有很好的參考價(jià)值。希望對(duì)大家有所幫助2017-11-11
Spring 開發(fā)過程中Value 注解的使用場(chǎng)景
這篇文章主要介紹了Spring 開發(fā)過程中Value 注解的使用場(chǎng)景,幫助大家更好的理解和使用spring框架,感興趣的朋友可以了解下2020-11-11
利用Java實(shí)現(xiàn)和可被K整除的子數(shù)組完整實(shí)例
這篇文章主要給大家介紹了關(guān)于利用Java實(shí)現(xiàn)和可被K整除的子數(shù)組的相關(guān)資料,這道題來自力扣,通過學(xué)習(xí)這道題的解題思路以及代碼對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-01-01
Spring JdbcTemplate整合使用方法及原理詳解
這篇文章主要介紹了Spring JdbcTemplate整合使用方法及原理詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08

