老生常谈系列之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文件,解释了调用的过程,这部分很简单,自己调试一下应该很快就能理清。
如果有人看到这里,那在这里老话重提。与君共勉,路漫漫其修远兮,吾将上下而求索。