老生常談系列之Aop--CGLIB動態代理的底層實現原理
老生常談系列之Aop--CGLIB動態代理的底層實現原理
前言
上一篇老生常談系列之Aop--JDK動態代理的底層實現原理簡單講解了JDK動態代理的實現,動態代理常用實現裡面的雙子星還有另一位--CGLIB,那麼這一篇就會介紹CGLIB動態代理。這篇文章還是複用之前老生常談系列之Aop--Spring Aop原理淺析文章的CGLIB部分的程式碼例子,CGLIB
的使用是非常簡單的,只需要自己實現一個MethodInterceptor
,然後使用Enhancer#create()
方法就可以建立一個動態代理處理,然後通過生成的代理類呼叫方法,即可實現Aop的效果。是不是很好奇為什麼可以這麼簡單,接下來我們來分析CGLIB
那麼接下來文章主要分為兩部分去解析
- 動態代理的生成過程
- 動態代理的呼叫過程
動態代理的生成
這一部分回答了動態代理是怎麼生成的,CGLIB
底層幫我們做了什麼。可以看到建立代理物件離不開Enhancer
類,那麼這個類的作用是什麼呢?摘取類上的註釋如下:
Generates dynamic subclasses to enable method interception. This class started as a substitute for the standard Dynamic Proxy support included with JDK 1.3, but one that allowed the proxies to extend a concrete base class, in addition to implementing interfaces. The dynamically generated subclasses override the non-final methods of the superclass and have hooks which callback to user-defined interceptor implementations.
翻譯一下:通過生成動態子類讓方法攔截生效。此類開始是作為 JDK 1.3 中包含的標準動態代理支援的替代品,但它允許代理擴充套件具體的基類,除了實現介面。動態生成的子類覆蓋超類的非final方法,並具有回撥到使用者定義的攔截器實現的鉤子。
簡而言之,就是生成一個代理子類,呼叫方法的時候回撥到自定義實現的攔截器裡。
首先我們來看簡單的示例程式碼
@Test public void cglibProxyTest(){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(CalculateServiceImpl.class); enhancer.setCallback(new MyMethodInterceptor()); CalculateService calculateService = (CalculateService) enhancer.create(); calculateService.calculate(); }
可以看到我們只需要設定superClass
和callback
後呼叫create()
方法就可以生成一個想要的物件。接下來就看一下create()
發生了什麼。
/**
* Generate a new class if necessary and uses the specified
* callbacks (if any) to create a new object instance.
* Uses the no-arg constructor of the superclass.
* @return a new instance
*/
public Object create() {
classOnly = false;
argumentTypes = null;
return createHelper();
}
可以看到這裡利用KEY_FACTORY
生成一個key
,這個key
封裝了多個值,屬於multi-valued keys
的實現。我們來看一下KeyFactory
的用法。
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;
}
KeyFactory
是類庫中重要的唯一標識生成器,用於CGLIB
實現快取時的key
,比較底層的基礎類。
摘取類上的註釋如下:
Generates classes to handle multi-valued keys, for use in things such as Maps and Sets.
To generate a <code>KeyFactory</code>, you need to supply an interface which
describes the structure of the key. The interface should have a
single method named <code>newInstance</code>, which returns an
<code>Object</code>. The arguments array can be
<i>anything</i>--Objects, primitive values, or single or
multi-dimension arrays of either. For example:
<p><pre>
private interface IntStringKey {
public Object newInstance(int i, String s);
}
</pre><p>
Once you have made a <code>KeyFactory</code>, you generate a new key by calling
the <code>newInstance</code> method defined by your interface.
<p><pre>
IntStringKey factory = (IntStringKey)KeyFactory.create(IntStringKey.class);
Object key1 = factory.newInstance(4, "Hello");
Object key2 = factory.newInstance(4, "World");
</pre><p>
翻譯一下:KeyFactory可以生成處理多值鍵的類,可以用於諸如 Maps 和 Sets 之類的東西。KeyFactory的使用也非常簡單,只需要提供一個介面,定義一個newInstance()
方法,呼叫(IntStringKey)KeyFactory.create(IntStringKey.class)
就可以生成一個key類。
接下來通過super.create(key)
呼叫父類的create(key)
方法。
protected Object create(Object key) {
try {
ClassLoader loader = getClassLoader();
Map<ClassLoader, ClassLoaderData> cache = CACHE;
// 先嚐試通過快取獲取ClassLoaderData
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;
// 這裡真正生成了代理類
Object obj = data.get(this, getUseCache());
if (obj instanceof Class) {
return firstInstance((Class) obj);
}
return nextInstance(obj);
}
// 省略異常
}
進入ClassLoaderData#get()
方法
public Object get(AbstractClassGenerator gen, boolean useCache) {
if (!useCache) {
return gen.generate(ClassLoaderData.this);
} else {
Object cachedValue = generatedClasses.get(gen);
return gen.unwrapCachedValue(cachedValue);
}
}
跟進generatedClasses.get(gen)
方法,這裡第一次進來,前面都會為空,所以會進行節點建立createEntry()
。
public V get(K key) {
final KK cacheKey = keyMapper.apply(key);
Object v = map.get(cacheKey);
if (v != null && !(v instanceof FutureTask)) {
return (V) v;
}
return createEntry(key, cacheKey, v);
}
可以看到這裡使用了FutureTask
去非同步執行建立,用於提升建立時候的效能。
protected V createEntry(final K key, KK cacheKey, Object v) {
FutureTask<V> task;
boolean creator = false;
if (v != null) {
// Another thread is already loading an instance
task = (FutureTask<V>) v;
} else {
// 建立一個FutureTask
task = new FutureTask<V>(new Callable<V>() {
public V call() throws Exception {
return loader.apply(key);
}
});
// 校驗這個任務是否已經存在
Object prevTask = map.putIfAbsent(cacheKey, task);
if (prevTask == null) {
// creator does the load
// 執行FutureTask
creator = true;
task.run();
} else if (prevTask instanceof FutureTask) {
task = (FutureTask<V>) prevTask;
} else {
return (V) prevTask;
}
}
V result;
try {
// 走到這裡說明是有正常執行的FutureTask,嘗試獲取FutureTask的結果
result = task.get();
}
// 省略部分異常
if (creator) {
map.put(cacheKey, result);
}
return result;
}
上面的程式碼跟著註釋看一下,重點在這裡loader.apply(key)
,這個loader
是new LoadingCache()
的時候傳入的。
task = new FutureTask<V>(new Callable<V>() {
public V call() throws Exception {
return loader.apply(key);
}
});
loader
的邏輯如下:
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);
跟進gen.generate(ClassLoaderData.this)
方法
protected Class generate(ClassLoaderData data) {
Class gen;
Object save = CURRENT.get();
CURRENT.set(this);
try {
ClassLoader classLoader = data.getClassLoader();
//省略部分邏輯和日誌,重點在這裡,這裡會生成代理類的位元組碼
byte[] b = strategy.generate(this);
String className = ClassNameReader.getClassName(new ClassReader(b));
ProtectionDomain protectionDomain = getProtectionDomain();
synchronized (classLoader) { // just in case
if (protectionDomain == null) {
gen = ReflectUtils.defineClass(className, b, classLoader);
} else {
gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
}
}
return gen;
}
// 省略異常
}
預設的實現是DefaultGeneratorStrategy
,可以看到這裡先獲取了一個DebuggingClassWriter
,CGLIB封裝ASM的處理類,用於生成class的byte流,通過GeneratorStrategy
回撥ClassGenerator.generateClass(DebuggingClassWriter)
,將自定義的class
物件的byte
處理回撥給具體的CGLIB上層操作類,比如由具體的BeanCopier
去控制位元組碼的生成。
public byte[] generate(ClassGenerator cg) throws Exception {
DebuggingClassWriter cw = getClassVisitor();
transform(cg).generateClass(cw);
return transform(cw.toByteArray());
}
在FastClassEmitter
類的建構函式裡,通過上面傳入的DebuggingClassWriter
封裝了ASM的相關操作,用於動態生成代理類的位元組碼,這裡不再深入ASM的原理,感興趣可以看位元組碼操作框架ASM的實現原理。
public void generateClass(ClassVisitor v) throws Exception {
new FastClassEmitter(v, getClassName(), type);
}
最後再通過transform(cw.toByteArray())
得到一個byte[]
陣列。好了,到這裡已經可以得到一個代理的位元組碼了。接下來回到AbstractClassGenerator#create()
方法裡。
// obj為已經獲取到的代理類,這裡是一個Class物件
Object obj = data.get(this, getUseCache());
if (obj instanceof Class) {
return firstInstance((Class) obj);
}
return nextInstance(obj);
只需要把物件例項化返回,至此,已經獲取了一個代理類。
protected Object firstInstance(Class type) {
return ReflectUtils.newInstance(type,
new Class[]{ Class.class },
new Object[]{ this.type });
}
動態代理的呼叫
程式碼樣例
這裡搞個例子HelloService
,HelloMethodInterceptor
對它增強。
public class HelloService {
public void sayHello(){
System.out.println("hello");
}
}
public class HelloMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before say hello...");
return methodProxy.invokeSuper(object,objects);
}
}
測試方法,把生成的代理類存下來。
public class HelloTest {
@Test
public void cglibProxyTest(){
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"C:\\my_study_project");
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HelloService.class);
enhancer.setCallback(new HelloMethodInterceptor());
HelloService helloService = (HelloService) enhancer.create();
helloService.sayHello();
}
}
那麼上面的步驟生產了什麼呢?我們來看一下生成的類有哪些。
HelloService$$EnhancerByCGLIB$$91933e33
是生成的代理類,HelloService$$FastClassByCGLIB$$a685f36d
是目標類的FastClass
,HelloService$$EnhancerByCGLIB$$91933e33$$FastClassByCGLIB$$33d595dd
是代理類的FastClass
。
反編譯後的程式碼
下面看一下每個類反編譯後的程式碼
代理類
每個類的程式碼都很長,這裡就不全部貼出來了,為了方便閱讀,這裡只留存sayHello()
和hashCode()
方法做比對闡述。如果想檢視全部的程式碼,自己把測試程式碼跑一下就能在相應的路徑下找到這三個class檔案。
package io.codegitz.service;
public class HelloService$$EnhancerByCGLIB$$91933e33 extends HelloService 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$sayHello$0$Method;
private static final MethodProxy CGLIB$sayHello$0$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
// 初始化該類的所有方法
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("io.codegitz.service.HelloService$$EnhancerByCGLIB$$91933e33");
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$hashCode$3$Method = var10000[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "()V"}, (var1 = Class.forName("io.codegitz.service.HelloService")).getDeclaredMethods())[0];
CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "()V", "sayHello", "CGLIB$sayHello$0");
}
// 呼叫目標類方法
final void CGLIB$sayHello$0() {
super.sayHello();
}
// 代理邏輯的方法
public final void sayHello() {
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$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
} else {
super.sayHello();
}
}
//hashCode方法也類似
final int CGLIB$hashCode$3() {
return super.hashCode();
}
public final int hashCode() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
return var1 == null ? 0 : ((Number)var1).intValue();
} else {
return super.hashCode();
}
}
// 生成MethodProxy,通過MethodProxy呼叫會生成fastClass,這是實現高效能呼叫的關鍵
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case 1535311470:
if (var10000.equals("sayHello()V")) {
return CGLIB$sayHello$0$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$3$Proxy;
}
}
return null;
}
// 初始化方法
static {
CGLIB$STATICHOOK1();
}
}
代理類fastClass
fastClass為所有的方法都建立了索引,在呼叫的時候通過傳入索引來尋找方法,進而避免反射的效能開銷,這是一種典型的空間換時間實現。
package io.codegitz.service;
import io.codegitz.service.HelloService..EnhancerByCGLIB..91933e33;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.reflect.FastClass;
public class HelloService$$EnhancerByCGLIB$$91933e33$$FastClassByCGLIB$$33d595dd extends FastClass {
public HelloService$$EnhancerByCGLIB$$91933e33$$FastClassByCGLIB$$33d595dd(Class var1) {
super(var1);
}
// 通過方法簽名獲取方法索引
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -1411842725:
if (var10000.equals("CGLIB$hashCode$3()I")) {
return 16;
}
break;
case 291273791:
if (var10000.equals("CGLIB$sayHello$0()V")) {
return 14;
}
break;
case 1535311470:
if (var10000.equals("sayHello()V")) {
return 7;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return 2;
}
}
return -1;
}
// 通過方法名獲取索引
public int getIndex(String var1, Class[] var2) {
switch(var1.hashCode()) {
case -2012993625:
if (var1.equals("sayHello")) {
switch(var2.length) {
case 0:
return 7;
}
}
break;
case -1983192202:
if (var1.equals("CGLIB$sayHello$0")) {
switch(var2.length) {
case 0:
return 14;
}
}
break;
case -29025555:
if (var1.equals("CGLIB$hashCode$3")) {
switch(var2.length) {
case 0:
return 16;
}
}
break;
case 147696667:
if (var1.equals("hashCode")) {
switch(var2.length) {
case 0:
return 2;
}
}
break;
}
return -1;
}
public int getIndex(Class[] var1) {
switch(var1.length) {
case 0:
return 0;
default:
return -1;
}
}
// 通過傳入方法的索引var1獲取方法執行
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
91933e33 var10000 = (91933e33)var2;
int var10001 = var1;
try {
switch(var10001) {
case 2:
return new Integer(var10000.hashCode());
case 7:
var10000.sayHello();
return null;
case 14:
var10000.CGLIB$sayHello$0();
return null;
case 16:
return new Integer(var10000.CGLIB$hashCode$3());
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
91933e33 var10000 = new 91933e33;
91933e33 var10001 = var10000;
int var10002 = var1;
try {
switch(var10002) {
case 0:
var10001.<init>();
return var10000;
}
} catch (Throwable var3) {
throw new InvocationTargetException(var3);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public int getMaxIndex() {
return 20;
}
}
目標類fastClass
CGLIB不僅對代理類生成fastClass,會對原有的目標類也會生成一個fastClass,原理是類似的,都是通過建立方法的索引,通過傳入索引尋找到方法,執行方法,避免了反射獲取方法的效能開銷。
package io.codegitz.service;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.reflect.FastClass;
public class HelloService$$FastClassByCGLIB$$a685f36d extends FastClass {
public HelloService$$FastClassByCGLIB$$a685f36d(Class var1) {
super(var1);
}
// 通過方法簽名獲取索引
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case 1535311470:
if (var10000.equals("sayHello()V")) {
return 0;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return 3;
}
}
return -1;
}
// 通過方法名獲取方法索引
public int getIndex(String var1, Class[] var2) {
switch(var1.hashCode()) {
case -2012993625:
if (var1.equals("sayHello")) {
switch(var2.length) {
case 0:
return 0;
}
}
break;
case 147696667:
if (var1.equals("hashCode")) {
switch(var2.length) {
case 0:
return 3;
}
}
}
return -1;
}
public int getIndex(Class[] var1) {
switch(var1.length) {
case 0:
return 0;
default:
return -1;
}
}
// 根據傳入的var1獲取對應的方法執行
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
HelloService var10000 = (HelloService)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
var10000.sayHello();
return null;
case 3:
return new Integer(var10000.hashCode());
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
HelloService var10000 = new HelloService;
HelloService var10001 = var10000;
int var10002 = var1;
try {
switch(var10002) {
case 0:
var10001.<init>();
return var10000;
}
} catch (Throwable var3) {
throw new InvocationTargetException(var3);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public int getMaxIndex() {
return 3;
}
}
呼叫過程分析
這些碼看起來是不是很亂?完全不知道從哪裡開始執行?
在開始程式碼分析之前,先看一下執行流程圖,步驟還是比較簡單明瞭
接著下一步,這裡就是進入動態代理類的邏輯,可以看HelloService$$EnhancerByCGLIB$$91933e33#sayHello()
方法。
public final void sayHello() {
// 獲取攔截器,這裡就是HelloMethodInterceptor
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
// 不為空,則執行攔截器
if (var10000 != null) {
// 注意這裡傳入的引數,這裡傳入了一個method和一個MethodProxy,這裡就會進入到自定義的HelloMethodInterceptor裡面的邏輯
var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
} else {
super.sayHello();
}
}
這裡是通過methodProxy.invokeSuper(object,objects)
,呼叫invokeSuper()
方法,注意這裡methodProxy
還有個invoke()
方法可以呼叫,那麼這兩者有什麼區別呢?顯而易見invokeSuper()
就是呼叫父類的方法,而invoke()
是呼叫代理經過攔截器的方法,如果呼叫invoke()
那麼每次都會走到攔截器,會造成死迴圈。
跟進methodProxy.invokeSuper()
方法,根據註釋可以看到,這裡就是呼叫了原有的沒有經過代理的方法。
/**
* Invoke the original (super) method on the specified object.
* @param obj the enhanced object, must be the object passed as the first
* argument to the MethodInterceptor
* @param args the arguments passed to the intercepted method; you may substitute a different
* argument array as long as the types are compatible
* @see MethodInterceptor#intercept
* @throws Throwable the bare exceptions thrown by the called method are passed through
* without wrapping in an <code>InvocationTargetException</code>
*/
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
可以看到,這裡的呼叫跟反射呼叫是有區別的。反射呼叫一般是直接把方法傳入,然後直接invoke()
,而這裡會先進行init()
,初始化一個FastClassInfo
,再通過fci.f2.invoke(fci.i2, obj, args)
去呼叫方法,這裡就是前面說的實現高效能呼叫的關鍵,這裡會為代理類方法和實現類的FastClass
,然後在呼叫時通過傳入方法的下標索引直接獲取方法執行,從而實現了空間換時間操作。
來看init()
方法,這個方法是用來初始化fastClassInfo
類的,詳細的初始化過程就不解析了,這裡只是最終生成了什麼就好。
private void init()
{
/*
* 使用 volatile 不變數允許我們以原子方式初始化 FastClass 和方法索引對
* Using a volatile invariant allows us to initialize the FastClass and
* method index pairs atomically.
*
* 雙重檢查鎖定在 Java 5 中使用 volatile 是安全的。在 1.5 之前,此程式碼可能允許多次例項化 fastClassInfo,這似乎是良性的。
* Double-checked locking is safe with volatile in Java 5. Before 1.5 this
* code could allow fastClassInfo to be instantiated more than once, which
* appears to be benign.
*/
if (fastClassInfo == null)
{
synchronized (initLock)
{
if (fastClassInfo == null)
{
CreateInfo ci = createInfo;
FastClassInfo fci = new FastClassInfo();
// 生成目標類fastClass
fci.f1 = helper(ci, ci.c1);
// 生成代理類fastClass
fci.f2 = helper(ci, ci.c2);
// 生成目標類index
fci.i1 = fci.f1.getIndex(sig1);
// 生成代理類index
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
}
}
}
以下是初始化時各個屬性的賦值
初始化完成後,就可以回到fci.f2.invoke(fci.i2, obj, args)
呼叫上了,可以看到fci.f2
的型別是HelloService$$EnhancerByCGLIB$$91933e33$$FastClassByCGLIB$$33d595dd
,也就是上面貼出來的代理類的fastClass
,來看一下這個類的invoke()
方法
檢視反編譯的invoke()
方法程式碼
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
91933e33 var10000 = (91933e33)var2;
int var10001 = var1;
try {
switch(var10001) {
case 2:
return new Integer(var10000.hashCode());
case 7:
var10000.sayHello();
return null;
case 16:
var10000.CGLIB$sayHello$0();
return null;
case 17:
return new Integer(var10000.CGLIB$hashCode$3());
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
這裡switch會匹配到16,然後執行var10000.CGLIB$sayHello$0()
,這個var10000
的型別是
找到HelloService$$EnhancerByCGLIB$$91933e33#CGLIB$sayHello$0()
方法,可以看到,這裡直接呼叫了HelloService#sayHello()
方法。同樣,methodProxy#invoke()
方法邏輯也是類似,注意區分呼叫的時候不要死迴圈就是了。
final void CGLIB$sayHello$0() {
super.sayHello();
}
到這裡,可以看到CGLIB生成的代理方法呼叫時,先經過呼叫攔截器,然後再呼叫到目標方法,其中methodProxy
呼叫目標方法時,會生成fastClass
,fastClass
中存有代理類和目標類的所有方法以及匹配的下標,通過傳入的下標就可以尋找到對應的方法,這裡的方法呼叫只需要第一次進來初始化fastClass
,後續可以直接呼叫,從而提高執行的效能,這也是CGLIB執行效率比JDK動態代理高的關鍵。這裡空間換時間的思想值得我們借鑑,適當地消耗記憶體來提升執行效率是完全值得的。
總結
回顧一下這篇文章,前半部分通過一個例子,大概講解了CGLIB生成一個代理類的步驟,但是具體整合ASM部分的位元組碼操作被略過,水平有效,不敢造次。挖了個坑,以後有能力再填。後半部分結合反編譯的class檔案,解釋了呼叫的過程,這部分很簡單,自己除錯一下應該很快就能理清。
如果有人看到這裡,那在這裡老話重提。與君共勉,路漫漫其修遠兮,吾將上下而求索。