文章目錄
- 前言
- 1. CGLib
- 1.1 代碼示例
- 1.2 原始碼閱讀
- 1.2.1 CGLib代理類的生成步驟
- 1.2.2 CGLib通過什么方式呼叫代理類的方法呢?
- 學而思
- 總結
前言
上一篇文章我們講了JDK動態代理及相關原始碼決議,我們了解了JDK動態代理的基本原理,JDK動態代理只代理介面,而CGLib可以代理任意一個目標類(對final類和方法無法代理),本文我們將探索CGLib如何使用及底層邏輯,
1. CGLib
CGLib (Code Generation Library) 是一個強大,高性能,高質量的Code生成類別庫,它可以在運行期擴展Java類、實作Java介面,
1.1 代碼示例
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
public class Bank {
public void transfer(String transferAmount) {
System.out.println("給目標賬戶執行轉賬" + transferAmount + "元···");
}
public void withdraw(String withdrawAmount) {
System.out.println("給客戶取款" + withdrawAmount + "元···");
}
}
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class ATM implements MethodInterceptor {
/**
* @param o 代理類
* @param method 攔截的方法
* @param objects 引數陣列
* @param methodProxy 對方法的代理
* @return o
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
operation(false);
methodProxy.invokeSuper(o, objects);
operation(true);
return o;
}
private void operation(boolean finishFlag) {
String currentStatus = finishFlag ? "業務處理完畢,收起銀行卡," : "開始業務操作···";
System.out.println(currentStatus);
}
}
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
public class Consumer {
static {
// 將執行程序中通過cglib動態生成的class檔案保存到本地
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "F:\\class");
}
public static void main(String[] args) {
ATM atm = new ATM();
Enhancer enhancer = new Enhancer();
// 設定父類(基于Business生成代理子類)
enhancer.setSuperclass(Bank.class);
// 設定回呼
enhancer.setCallback(atm);
Bank business = (Bank) enhancer.create();
business.transfer("200");
business.withdraw("20000000000000");
}
}
開始業務操作···
給目標賬戶執行轉賬200元···
業務處理完畢,收起銀行卡,
開始業務操作···
給客戶取款20000000000000元···
業務處理完畢,收起銀行卡,
1.2 原始碼閱讀
1.2.1 CGLib代理類的生成步驟
首先我們先查看Enhancer.create()主要做了那些事:
// net.sf.cglib.proxy.Enhancer
public class Enhancer extends AbstractClassGenerator{
// 代碼部分省略
private static final EnhancerKey KEY_FACTORY =
(EnhancerKey)KeyFactory.create(EnhancerKey.class, KeyFactory.HASH_ASM_TYPE, null);
/** Internal interface, only public due to ClassLoader issues. */
public interface EnhancerKey {
public Object newInstance(String type,
String[] interfaces,
WeakCacheKey<CallbackFilter> filter,
Type[] callbackTypes,
boolean useFactory,
boolean interceptDuringConstruction,
Long serialVersionUID);
}
/**
* 設定被代理的類,
* 如果superclass是一個介面,則使用setInterfaces.
* 非介面實參不能宣告為final,并且必須有一個可以訪問的構造引數
* @param superclass 被代理的類或介面
*/
public void setSuperclass(Class superclass) {
if (superclass != null && superclass.isInterface()) {
setInterfaces(new Class[]{ superclass });
} else if (superclass != null && superclass.equals(Object.class)) {
this.superclass = null;
} else {
this.superclass = superclass;
}
}
public void setInterfaces(Class[] interfaces) {
this.interfaces = interfaces;
}
/**
* 設定代理類的方法映射到特定回呼索引
*/
public void setCallbackFilter(CallbackFilter filter) {
this.filter = filter;
}
/**
* 設定單個回呼
*/
public void setCallback(final Callback callback) {
setCallbacks(new Callback[]{ callback });
}
/**
* 設定回呼陣列,
* 設定該方法的同時必須使用CallbackFilter
* 來指定代理類中每個方法在對應的回呼索引,
*/
public void setCallbacks(Callback[] callbacks) {
if (callbacks != null && callbacks.length == 0) {
throw new IllegalArgumentException("Array cannot be empty");
}
this.callbacks = callbacks;
}
/**
* 生成代理類,并使用指定回呼,
* @return 回傳代理類實體
*/
public Object create() {
classOnly = false;
argumentTypes = null;
return createHelper();
}
private Object createHelper() {
preValidate();
Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
ReflectUtils.getNames(interfaces),
filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
callbackTypes,
useFactory,
interceptDuringConstruction,
serialVersionUID);
this.currentKey = key;
Object result = super.create(key);
return result;
}
// 代碼部分省略
}
呼叫Enhancer.create()時大致流程如下:
- 呼叫
createHelper()方法然后進行前置條件檢查; - 呼叫
Enhancer內部介面EnhancerKey的newInstance(···)生成唯一key(用于從快取中獲取代理類實體), - 然后通過
super.create(key)獲取我們設定的SuperClass對應的代理類實體,
下面我們繼續跟進AbstractClassGenerator.create()原始碼如下:
// net.sf.cglib.core.AbstractClassGenerator
abstract public class AbstractClassGenerator<T> implements ClassGenerator{
// 部分省略
protected Object create(Object key) {
try {
// 獲得類加載器 loader作為快取key
ClassLoader loader = getClassLoader();
Map<ClassLoader, ClassLoaderData> cache = CACHE;
// 根據類加載器獲取快取
ClassLoaderData data = cache.get(loader);
if (data == null) {
synchronized (AbstractClassGenerator.class) {
cache = CACHE;
data = cache.get(loader);
if (data == null) {
Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
data = new ClassLoaderData(loader);
newCache.put(loader, data);
CACHE = newCache;
}
}
}
this.key = key;
// getUseCache()默認為true,用于設值是否啟用快取
Object obj = data.get(this, getUseCache());
if (obj instanceof Class) {
// 實體化并回傳
return firstInstance((Class) obj);
}
return nextInstance(obj);
} catch (RuntimeException e) {
throw e;
} catch (Error e) {
throw e;
} catch (Exception e) {
throw new CodeGenerationException(e);
}
}
// 省略部分代碼
}
AbstractClassGenerator.create(key)流程大致如下:
- 通過類加載器從
CACHE中獲取對應快取,若根據類加載器未獲取到快取,則初始化后放入快取;// AbstractClassGenerator.create()部分代碼片段 cache = CACHE; data = cache.get(loader); if (data == null) { Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache); data = new ClassLoaderData(loader); newCache.put(loader, data); CACHE = newCache; } ClassLoaderData是AbstractClassGenerator的內部類,通過data.get(this, getUseCache())從快取獲取Class實體或通過asm生成位元組碼檔案回傳Class實體,
最后一步很關鍵data.get(this, getUseCache()),原始碼如下:
// AbstractClassGenerator內部類ClassLoaderData原始碼
protected static class ClassLoaderData {
// 部分代碼省略
private final LoadingCache<AbstractClassGenerator, Object, Object> generatedClasses;
private final WeakReference<ClassLoader> classLoader;
// 部分代碼省略
private static final Function<AbstractClassGenerator, Object> GET_KEY = new Function<AbstractClassGenerator, Object>() {
public Object apply(AbstractClassGenerator gen) {
return gen.key;
}
};
public ClassLoaderData(ClassLoader classLoader) {
if (classLoader == null) {
throw new IllegalArgumentException("classLoader == null is not yet supported");
}
this.classLoader = new WeakReference<ClassLoader>(classLoader);
Function<AbstractClassGenerator, Object> load =
new Function<AbstractClassGenerator, Object>() {
public Object apply(AbstractClassGenerator gen) {
// 生成位元組碼檔案,載入并初始化回傳Class實體
Class klass = gen.generate(ClassLoaderData.this);
return gen.wrapCachedClass(klass);
}
};
generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load);
}
public Object get(AbstractClassGenerator gen, boolean useCache) {
// 判斷是否通過快取獲取
if (!useCache) {
return gen.generate(ClassLoaderData.this);
} else {
Object cachedValue = generatedClasses.get(gen);
return gen.unwrapCachedValue(cachedValue);
}
}
}
data.get(this, getUseCache())大致流程如下:
-
useCache=true則generatedClasses.get(gen)從快取獲取,若快取不存在則通過gen.generate()創建Class實體后放入快取,// net.sf.cglib.core.internal.LoadingCache部分原始碼 public class LoadingCache<K, KK, V> { protected final ConcurrentMap<KK, Object> map; protected final Function<K, V> loader; protected final Function<K, KK> keyMapper; // 部分省略 // V : 代理類的Class // KK : 生成Key的類 // K : AbstractClassGenerator public V get(K key) { // 生成cacheKey并從ConcurrentMap<KK, Object> map中獲取代理類的Class final KK cacheKey = keyMapper.apply(key); Object v = map.get(cacheKey); if (v != null && !(v instanceof FutureTask)) { return (V) v; } // 未獲取到則創建Class并放入快取 return createEntry(key, cacheKey, v); } protected V createEntry(final K key, KK cacheKey, Object v) { FutureTask<V> task; boolean creator = false; // 代碼部分省略 task = new FutureTask<V>(new Callable<V>() { public V call() throws Exception { // 生成class return loader.apply(key); } }); Object prevTask = map.putIfAbsent(cacheKey, task); if (prevTask == null) { creator = true; task.run(); } else if (prevTask instanceof FutureTask) { task = (FutureTask<V>) prevTask; } else { return (V) prevTask; } V result = task.get(); // 代碼部分省略 if (creator) { // 放入快取 map.put(cacheKey, result); } return result; } }// loader.apply(key)的實作是在ClassLoaderData構造方法中 public Object apply(AbstractClassGenerator gen) { Class klass = gen.generate(ClassLoaderData.this); return gen.wrapCachedClass(klass); } -
否則直接
gen.generate(ClassLoaderData.this)生成位元組碼檔案,載入并初始化回傳Class實體,
OK,繼續跟進gen.generate(ClassLoaderData.this)這塊的代碼邏輯:
// AbstractClassGenerator部分代碼片段
protected Class generate(ClassLoaderData data) {
Class gen;
Object save = CURRENT.get();
CURRENT.set(this);
try {
ClassLoader classLoader = data.getClassLoader();
if (classLoader == null) {
throw new IllegalStateException("ClassLoader is null while trying to define class " + getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " + "Please file an issue at cglib's issue tracker.");
}
synchronized (classLoader) {
// 生成類名
String name = generateClassName(data.getUniqueNamePredicate());
data.reserveName(name);
this.setClassName(name);
}
// 通過類加載器嘗試加載getClassName(),加載不到拋出例外繼續向下執行
if (attemptLoad) {
try {
// ClassLoader.loadClass(classname,false):將位元組碼檔案加載到JVM中,false:標識不進行連接,即不會被初始化,默認false
// Class.forName(className,true,classloader):除了將位元組碼檔案加載到JVM中,true標識:自動初始化,默認為true
gen = classLoader.loadClass(getClassName());
return gen;
} catch (ClassNotFoundException e) {
// ignore
}
}
// 生成位元組碼陣列
byte[] b = strategy.generate(this);
String className = ClassNameReader.getClassName(new ClassReader(b));
ProtectionDomain protectionDomain = getProtectionDomain();
synchronized (classLoader) { // just in case
// 將上面生成的位元組碼加載到記憶體回傳Class實體
// Class.forName(className, true, loader);
if (protectionDomain == null) {
gen = ReflectUtils.defineClass(className, b, classLoader);
} else {
gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
}
}
return gen;
} catch (RuntimeException e) {
throw e;
} catch (Error e) {
throw e;
} catch (Exception e) {
throw new CodeGenerationException(e);
} finally {
CURRENT.set(save);
}
}
大致流程如下:
- 生成類名稱,生成規則:類全限定名+來源+16進制的hash值:
// net.sf.cglib.core.DefaultNamingPolicy 部分代碼片段 public String getClassName(String prefix, String source, Object key, Predicate names) { if (prefix == null) { prefix = "net.sf.cglib.empty.Object"; } else if (prefix.startsWith("java")) { prefix = "$" + prefix; } String base = prefix + "$$" + source.substring(source.lastIndexOf('.') + 1) + getTag() + "$$" + Integer.toHexString(STRESS_HASH_CODE ? 0 : key.hashCode()); String attempt = base; int index = 2; while (names.evaluate(attempt)) attempt = base + "_" + index++; return attempt; } - 通過類加載器嘗試加載上面生成的類名稱,成功就回傳,失敗則繼續執行,
- 通過asm框架工具類DefaultGeneratorStrategy生成位元組碼陣列(涉及的內容較多,本文不展開閱讀),通過Class.forName()轉換為Class,
// net.sf.cglib.core.ReflectUtils部分原始碼 public static Class defineClass(String className, byte[] b, ClassLoader loader, ProtectionDomain protectionDomain) throws Exception { Class c; if (DEFINE_CLASS != null) { Object[] args = new Object[]{className, b, new Integer(0), new Integer(b.length), protectionDomain }; c = (Class)DEFINE_CLASS.invoke(loader, args); } else if (DEFINE_CLASS_UNSAFE != null) { Object[] args = new Object[]{className, b, new Integer(0), new Integer(b.length), loader, protectionDomain }; c = (Class)DEFINE_CLASS_UNSAFE.invoke(UNSAFE, args); } else { throw new CodeGenerationException(THROWABLE); } // Force static initializers to run. Class.forName(className, true, loader); return c; }
至此CGLib生成代理類的流程我們通過以上原始碼都大致了解了,那么它的呼叫程序呢?
1.2.2 CGLib通過什么方式呼叫代理類的方法呢?
在代碼示例中我們通過配置DEBUG_LOCATION_PROPERTY的值來保存CGLib生成的檔案,查看對應路徑下的檔案如下:
// System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "輸出路徑")
// 1.代理類的FastClass類
Bank$$EnhancerByCGLIB$$406a1aa1$$FastClassByCGLIB$$7a777fd6.class
// 2.代理類
Bank$$EnhancerByCGLIB$$406a1aa1.class
// 3.被代理的FastClass類
Bank$$FastClassByCGLIB$$75312cb7.class
接下來我們先查看生成的代理類原始碼(我是通過IDEA打開,可以自行選擇):
public class Bank$$EnhancerByCGLIB$$406a1aa1 extends Bank 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;
// 通過enhancer.setCallback設定的對應攔截器
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
// 代理類方法 每個方法對應一個Method 及 MethodProxy
private static final Method CGLIB$transfer$0$Method;
private static final MethodProxy CGLIB$transfer$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$withdraw$1$Method;
private static final MethodProxy CGLIB$withdraw$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("demo6.Bank$$EnhancerByCGLIB$$406a1aa1");
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[]{"transfer", "(Ljava/lang/String;)V", "withdraw", "(Ljava/lang/String;)V"}, (var1 = Class.forName("demo6.Bank")).getDeclaredMethods());
CGLIB$transfer$0$Method = var10000[0];
CGLIB$transfer$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)V", "transfer", "CGLIB$transfer$0");
CGLIB$withdraw$1$Method = var10000[1];
CGLIB$withdraw$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)V", "withdraw", "CGLIB$withdraw$1");
}
// 直接呼叫父類方法
final void CGLIB$transfer$0(String var1) {
super.transfer(var1);
}
// 設定了攔截器則呼叫對應攔截器的intercept()方法
public final void transfer(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$transfer$0$Method, new Object[]{var1}, CGLIB$transfer$0$Proxy);
} else {
super.transfer(var1);
}
}
// 如上類似
final void CGLIB$withdraw$1(String var1) {
super.withdraw(var1);
}
// 如上類似
public final void withdraw(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$withdraw$1$Method, new Object[]{var1}, CGLIB$withdraw$1$Proxy);
} else {
super.withdraw(var1);
}
}
// 省略clone() toString() hashCode() equals() 部分原始碼
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -566439627:
if (var10000.equals("withdraw(Ljava/lang/String;)V")) {
return CGLIB$withdraw$1$Proxy;
}
break;
// 部分省略···
case 447064820:
if (var10000.equals("transfer(Ljava/lang/String;)V")) {
return CGLIB$transfer$0$Proxy;
}
break;
// 部分省略···
}
return null;
}
public Bank$$EnhancerByCGLIB$$406a1aa1() {
CGLIB$BIND_CALLBACKS(this);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
Bank$$EnhancerByCGLIB$$406a1aa1 var1 = (Bank$$EnhancerByCGLIB$$406a1aa1)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}
}
// 部分省略···
static {
CGLIB$STATICHOOK1();
}
}
回顧一下我們的示例代碼:
- demo示例中,我們通過
enhancer.create()獲得代理類實體Bank$$EnhancerByCGLIB$$406a1aa1(如上原始碼),在初始化的程序中會為每個方法生成對應的Method與MethodProxy,static { CGLIB$STATICHOOK1(); } - 接下來呼叫
transfer()方法時判斷是否設定攔截器,在設定攔截器的情況下判斷分支會執行到var10000.intercept();// Bank$$EnhancerByCGLIB$$406a1aa1 部分原始碼 public final void transfer(String var1) { // 指定的攔截器否則非null MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { // 引數釋義分別是:代理類、攔截的方法、引數、方法代理 var10000.intercept(this, CGLIB$transfer$0$Method, new Object[]{var1}, CGLIB$transfer$0$Proxy); } else { super.transfer(var1); } } - 然后呼叫攔截器ATM.intercept()方法,列印
開始業務操作···public class ATM implements MethodInterceptor { /** * @param o 增強的物件 * @param method 攔截的方法 * @param objects 引數陣列 * @param methodProxy 對方法的代理 * @return o */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { operation(false); methodProxy.invokeSuper(o, objects); operation(true); return o; } private void operation(boolean finishFlag) { String currentStatus = finishFlag ? "業務處理完畢,收起銀行卡," : "開始業務操作···"; System.out.println(currentStatus); } } - 然后通過
methodProxy.invokeSuper(o, objects)呼叫父類方法,
methodProxy.invokeSuper(o, objects)如何呼叫父類方法呢?
// et.sf.cglib.proxy.MethodProxy
public class MethodProxy {
// 方法簽名
private Signature sig1;
private Signature sig2;
private CreateInfo createInfo;
private final Object initLock = new Object();
private volatile FastClassInfo fastClassInfo;
/**
* @param c1 被代理物件
* @param c2 代理物件
* @param desc 引數描述
* @param name1 被代理方法
* @param name2 代理方法
*/
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
MethodProxy proxy = new MethodProxy();
proxy.sig1 = new Signature(name1, desc);
proxy.sig2 = new Signature(name2, desc);
proxy.createInfo = new CreateInfo(c1, c2);
return proxy;
}
private static class FastClassInfo {
// 被代理物件FastClass
FastClass f1;
// 代理物件FastClass
FastClass f2;
// 被代理物件方法索引
int i1;
// 代理物件方法索引
int i2;
}
private static class CreateInfo {
Class c1;
Class c2;
NamingPolicy namingPolicy;
GeneratorStrategy strategy;
boolean attemptLoad;
public CreateInfo(Class c1, Class c2) {
this.c1 = c1;
this.c2 = c2;
AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
if (fromEnhancer != null) {
namingPolicy = fromEnhancer.getNamingPolicy();
strategy = fromEnhancer.getStrategy();
attemptLoad = fromEnhancer.getAttemptLoad();
}
}
}
// 部分代碼省略
// 被代理類FastClass通過被代理物件方法索引呼叫代理類方法
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (IllegalArgumentException e) {
if (fastClassInfo.i1 < 0)
throw new IllegalArgumentException("Protected method: " + sig1);
throw e;
}
}
/**
* 代理類FastClass通過代理物件方法索引,實際呼叫代理類父類方法
*
* @param obj 代理類
* @param args 引數陣列
*/
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
// 初始化
init();
FastClassInfo fci = fastClassInfo;
// 呼叫代理物件FastClass.invoke方法(也就是我們上面看到的生成檔案Bank$$EnhancerByCGLIB$$406a1aa1$$FastClassByCGLIB$$7a777fd6物件)
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
// 創建被代理物件FastClass(f1)、代理物件fastClass(f2)、被代理物件方法(i1)、代理物件方法(i2)
private void init() {
if (fastClassInfo == null) {
synchronized (initLock) {
if (fastClassInfo == null) {
CreateInfo ci = createInfo;
FastClassInfo fci = new FastClassInfo();
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(sig1);
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
}
}
}
}
methodProxy.invokeSuper(o, objects)大致流程如下:
init()創建被代理物件FastClass與代理物件fastClass、獲取被代理物件方法索引與代理物件方法索引- 通過
ci.f2.invoke(fci.i2, obj, args),代理類FastClass通過代理物件方法索引,呼叫代理類父類方法,
打開生成的代理類FastClass部分原始碼如下:
public class Bank$$EnhancerByCGLIB$$406a1aa1$$FastClassByCGLIB$$7a777fd6 extends FastClass {
public Bank$$EnhancerByCGLIB$$406a1aa1$$FastClassByCGLIB$$7a777fd6(Class var1) {
super(var1);
}
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
// 省略
case -566439627:
if (var10000.equals("withdraw(Ljava/lang/String;)V")) {
return 9;
}
break;
case 123475845:
if (var10000.equals("CGLIB$transfer$0(Ljava/lang/String;)V")) {
return 20;
}
break;
// 省略
}
return -1;
}
public int getIndex(String var1, Class[] var2) {
switch(var1.hashCode()) {
case -1958972742:
if (var1.equals("CGLIB$transfer$0")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.String")) {
return 20;
}
}
}
break;
case -1861191142:
if (var1.equals("CGLIB$withdraw$1")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.String")) {
return 18;
}
}
}
break;
// 省略
}
return -1;
}
public int getIndex(Class[] var1) {
switch(var1.length) {
case 0:
return 0;
default:
return -1;
}
}
/**
* @var1 方法索引
* @var2 代理類
* @var3 引數
*/
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
406a1aa1 var10000 = (406a1aa1)var2;
int var10001 = var1;
try {
switch(var10001) {
case 18:
var10000.CGLIB$withdraw$1((String)var3[0]);
return null;
case 20:
var10000.CGLIB$transfer$0((String)var3[0]);
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
// 省略
}
通過以上代理類FastClass原始碼我們可以看到,在呼叫時通過方法索引找到對應方法,然后呼叫代理類的CGLIB$transfer$0((String)var3[0])方法完成最終呼叫,呼叫完畢最終輸出“業務處理完畢,收起銀行卡”,至此整個流程結束,
// Bank$$EnhancerByCGLIB$$406a1aa1代理類部分原始碼
// 直接呼叫父類方法
final void CGLIB$transfer$0(String var1) {
super.transfer(var1);
}
學而思
將代碼示例中ATM的methodProxy.invokeSuper()修改為methodProxy.invoke()將會導致StackOverflowError,這是什么原因呢?有興趣的同學可以自行研究一下,找到對應的解決方式,
總結
通過原始碼閱讀的方式,我們了解了代理類生成的生成邏輯與最終如何呼叫被代理類目標方法的邏輯,形成了對CGLib從模糊到清晰的印象,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/263800.html
標籤:java
下一篇:【閑來無事】微博熱搜實時資料圖表
