文章目录
概述
CGLIB是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架(Spring、dynaop)中,用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架,同样使用CGLIB来代理单端(多对一和一对一)关联(延迟提取集合使用的另一种机制)。CGLIB作为一个开源项目,其代码托管在github。
CGLIB代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问。我们知道Java中有一个动态代理也是做这个事情的,那我们为什么不直接使用Java动态代理,而要使用CGLIB呢?答案是CGLIB相比于JDK动态代理更加强大,JDK动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理。如果要代理的类为一个普通类、没有接口,那么Java动态代理就没法使用了。
CGLIB组织结构
CGLIB底层使用了ASM(一个短小精悍的字节码操作框架)来操作字节码生成新的类。除了CGLIB库外,脚本语言(如Groovy何BeanShell)也使用ASM生成字节码。ASM使用类似SAX的解析器来实现高性能。我们不鼓励直接使用ASM,因为它需要对Java字节码的格式足够的了解。
CGLIB动态代理示例
要使用CGLIB动态代理,肯定要引入cglib-x.x.x.jar,而CGLIB底层用ASM来操作字节码,因此也要引入asm-x.x.x.jar。(这里用cglib-2.2.2.jar和asm-3.1.jar)
maven依赖坐标为(maven会引入cglib的传递依赖)
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
被代理类:
public class HelloService {
public String hello(String name) {
return "hello," + name;
}
public String hi(String msg) {
return "hi,"+msg;
}
}
方法拦截器:
public class HelloServiceInterceptor implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class<?> clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
System.out.println("动态代理预处理...");
System.out.println("被拦截方法:" + arg1.getName());
Object result = arg3.invokeSuper(arg0, arg2);
System.out.println(result);
System.out.println("动态代理后处理...");
return result;
}
}
测试:
public class CglibDynamicProxy {
public static void main(String[] args) {
HelloService proxy = (HelloService)(new HelloServiceInterceptor().getProxy(HelloService.class));
proxy.hello("张三");
proxy.hi("cglib动态代理");
}
}
输出:
动态代理预处理...
被拦截方法:hello
hello,张三
动态代理后处理...
动态代理预处理...
被拦截方法:hi
hi,cglib动态代理
动态代理后处理...
JDK代理要求被代理的类必须实现接口,有很强的局限性。而CGLIB动态代理则没有此类强制性要求。简单的说,CGLIB会让生成的代理类继承被代理类,并在代理类中对代理方法进行强化处理(前置处理、后置处理等)。在CGLIB底层,其实是借助了ASM这个非常强大的Java字节码生成框架。
分析
与JDK动态代理相比,CGLIB可以实现对一般类的代理而无需实现接口。在上例中通过下列步骤来生成目标类Target的代理类:
- 创建Enhancer实例;
- 通过setSuperclass方法来设置目标类;
- 通过setCallback方法来设置拦截对象;
- create方法生成Target的代理类,并返回代理类的实例。
Enhancer可能是CGLIB中最常用的一个类,和Java1.3动态代理中引入的Proxy类差不多。和Proxy不同的是,Enhancer既能够代理普通的class,也能够代理接口。Enhancer创建一个被代理对象的子类并且拦截所有的方法调用(包括从Object中继承的toString和hashCode方法)。Enhancer不能够拦截final方法,例如Object.getClass()方法,这是由于Java final方法语义决定的。基于同样的道理,Enhancer也不能对fianl类进行代理操作。这也是Hibernate为什么不能持久化final class的原因。
代理类分析
CGLIB动态代理默认不生成代理相关Class文件,可以设置参数
-Dcglib.debugLocation=H:\EclipseWorkspace\proxy-test\bin\cglib
或
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, “H:\EclipseWorkspace\proxy-test\bin\cglib”);
来生成代理类Class文件。
这里稍微提一下代理类生成的调用链:
- Enhancer : create()
- Enhancer : createHelper()
- AbstractClassGenerator : create(Object key)
- DefaultGeneratorStrategy : generate(ClassGenerator cg)
- Enhancer : generateClass(ClassVisitor v)
最终Enhancer类generateClass(ClassVisitor v)方法生成代理类,至于生成代理类Class文件是在DefaultGeneratorStrategy类的generate(ClassGenerator cg)方法:
return transform(cw.toByteArray());
cw.toByteArray()调用的是DebuggingClassWriter类的toByteArray()方法:
public byte[] toByteArray() {
return (byte[]) java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
byte[] b = DebuggingClassWriter.super.toByteArray();
if (debugLocation != null) {
String dirs = className.replace('.', File.separatorChar);
try {
new File(debugLocation + File.separatorChar + dirs).getParentFile().mkdirs();
File file = new File(new File(debugLocation), dirs + ".class");
OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
try {
out.write(b);
} finally {
out.close();
}
......
上面方法中可以看到当debugLocation != null时将Class字节数组b写到debugLocation目录下,而这里的debugLocation在该类静态代码块中初始化:
public static final String DEBUG_LOCATION_PROPERTY = "cglib.debugLocation";
static {
debugLocation = System.getProperty(DEBUG_LOCATION_PROPERTY);
if (debugLocation != null) {
System.err.println("CGLIB debugging enabled, writing to '" + debugLocation + "'");
try {
Class.forName("org.objectweb.asm.util.TraceClassVisitor");
traceEnabled = true;
} catch (Throwable ignore) {
}
}
}
因此我们可以设置参数cglib.debugLocation来控制代理类生成路径。
反编译代理类HelloService E n h a n c e r B y C G L I B EnhancerByCGLIB EnhancerByCGLIBdf0ac471
package cglib;
import cglib.HelloService;
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;
public class HelloService$$EnhancerByCGLIB$$df0ac471 extends HelloService implements Factory {
private boolean CGLIB$BOUND;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static final Method CGLIB$hello$0$Method;
private static final MethodProxy CGLIB$hello$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$hi$1$Method;
private static final MethodProxy CGLIB$hi$1$Proxy;
private static final Method CGLIB$finalize$2$Method;
private static final MethodProxy CGLIB$finalize$2$Proxy;
private static final Method CGLIB$equals$3$Method;
private static final MethodProxy CGLIB$equals$3$Proxy;
private static final Method CGLIB$toString$4$Method;
private static final MethodProxy CGLIB$toString$4$Proxy;
private static final Method CGLIB$hashCode$5$Method;
private static final MethodProxy CGLIB$hashCode$5$Proxy;
private static final Method CGLIB$clone$6$Method;
private static final MethodProxy CGLIB$clone$6$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("cglib.HelloService$$EnhancerByCGLIB$$df0ac471");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$finalize$2$Method = var10000[0];
CGLIB$finalize$2$Proxy = MethodProxy.create(var1, var0, "()V", "finalize", "CGLIB$finalize$2");
CGLIB$equals$3$Method = var10000[1];
CGLIB$equals$3$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$3");
CGLIB$toString$4$Method = var10000[2];
CGLIB$toString$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$4");
CGLIB$hashCode$5$Method = var10000[3];
CGLIB$hashCode$5$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$5");
CGLIB$clone$6$Method = var10000[4];
CGLIB$clone$6$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$6");
var10000 = ReflectUtils.findMethods(new String[]{"hello", "(Ljava/lang/String;)Ljava/lang/String;", "hi", "(Ljava/lang/String;)Ljava/lang/String;"}, (var1 = Class.forName("cglib.HelloService")).getDeclaredMethods());
CGLIB$hello$0$Method = var10000[0];
CGLIB$hello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "hello", "CGLIB$hello$0");
CGLIB$hi$1$Method = var10000[1];
CGLIB$hi$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "hi", "CGLIB$hi$1");
}
final String CGLIB$hello$0(String var1) {
return super.hello(var1);
}
public final String hello(String var1) {
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$hello$0$Method, new Object[]{var1}, CGLIB$hello$0$Proxy):super.hello(var1);
}
final String CGLIB$hi$1(String var1) {
return super.hi(var1);
}
public final String hi(String var1) {
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$hi$1$Method, new Object[]{var1}, CGLIB$hi$1$Proxy):super.hi(var1);
}
final void CGLIB$finalize$2() throws Throwable {
super.finalize();
}
protected final void finalize() throws Throwable {
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$finalize$2$Method, CGLIB$emptyArgs, CGLIB$finalize$2$Proxy);
} else {
super.finalize();
}
}
final boolean CGLIB$equals$3(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$3$Method, new Object[]{var1}, CGLIB$equals$3$Proxy);
return var2 == null?false:((Boolean)var2).booleanValue();
} else {
return super.equals(var1);
}
}
final String CGLIB$toString$4() {
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$4$Method, CGLIB$emptyArgs, CGLIB$toString$4$Proxy):super.toString();
}
final int CGLIB$hashCode$5() {
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$5$Method, CGLIB$emptyArgs, CGLIB$hashCode$5$Proxy);
return var1 == null?0:((Number)var1).intValue();
} else {
return super.hashCode();
}
}
final Object CGLIB$clone$6() 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$6$Method, CGLIB$emptyArgs, CGLIB$clone$6$Proxy):super.clone();
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -1574182249:
if(var10000.equals("finalize()V")) {
return CGLIB$finalize$2$Proxy;
}
break;
case -1090657086:
if(var10000.equals("hi(Ljava/lang/String;)Ljava/lang/String;")) {
return CGLIB$hi$1$Proxy;
}
break;
case -508378822:
if(var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$6$Proxy;
}
break;
case 848333779:
if(var10000.equals("hello(Ljava/lang/String;)Ljava/lang/String;")) {
return CGLIB$hello$0$Proxy;
}
break;
case 1826985398:
if(var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$3$Proxy;
}
break;
case 1913648695:
if(var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$4$Proxy;
}
break;
case 1984935277:
if(var10000.equals("hashCode()I")) {
return CGLIB$hashCode$5$Proxy;
}
}
return null;
}
public HelloService$$EnhancerByCGLIB$$df0ac471() {
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) {
HelloService$$EnhancerByCGLIB$$df0ac471 var1 = (HelloService$$EnhancerByCGLIB$$df0ac471)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);
HelloService$$EnhancerByCGLIB$$df0ac471 var10000 = new HelloService$$EnhancerByCGLIB$$df0ac471();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
HelloService$$EnhancerByCGLIB$$df0ac471 var10000 = new HelloService$$EnhancerByCGLIB$$df0ac471();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
HelloService$$EnhancerByCGLIB$$df0ac471 var10000 = new HelloService$$EnhancerByCGLIB$$df0ac471;
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();
}
}
可以看到代理类HelloService
E
n
h
a
n
c
e
r
B
y
C
G
L
I
B
EnhancerByCGLIB
EnhancerByCGLIBdf0ac471继承了目标类HelloService,实现了Factory接口。
可以看到CGLIB除了HelloService类的hello,hi两个方法,也代理Object类的finalize,equals,toString,hashCode,clone五个方法。
代理类为每个目标类的方法生成两个方法,例如针对目标类中的每个非private方法,代理类会生成两个方法,以hello方法为例:一个是@Override的hello方法,一个是CGLIB$hello
0
(
C
G
L
I
B
0(CGLIB
0(CGLIBhello$0相当于目标类的hello方法)。在示例代码中调用目标类的方法proxy.hello()时,实际上调用的是代理类中的hello()方法。接下来着重分析代理类中的hello方法,看看是怎么实现的代理功能。
public final String hello(String var1) {
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$hello$0$Method, new Object[]{var1}, CGLIB$hello$0$Proxy):super.hello(var1);
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
HelloService$$EnhancerByCGLIB$$df0ac471 var1 = (HelloService$$EnhancerByCGLIB$$df0ac471)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];
}
}
可以看到在CGLIB
B
I
N
D
C
A
L
L
B
A
C
K
S
方
法
中
,
从
C
G
L
I
B
BIND_CALLBACKS方法中,从CGLIB
BINDCALLBACKS方法中,从CGLIBTHREAD_CALLBACKS获取拦截器,若获取不到,则从CGLIB
S
T
A
T
I
C
C
A
L
L
B
A
C
K
S
获
取
,
那
么
拦
截
器
是
如
何
设
置
到
C
G
L
I
B
STATIC_CALLBACKS获取,那么拦截器是如何设置到CGLIB
STATICCALLBACKS获取,那么拦截器是如何设置到CGLIBTHREAD_CALLBACKS 或者 CGLIB$STATIC_CALLBACKS中的呢?
在JDK动态代理中拦截对象是在实例化代理类时由构造函数传入的,在CGLIB中是调用Enhancer的firstInstance方法来生成代理类实例并设置拦截器的。
firstInstance的调用轨迹为:
- Enhancer:firstInstance
- Enhancer:createUsingReflection
- Enhancer:setThreadCallbacks
- Enhancer:setCallbacksHelper
- HelloService E n h a n c e r B y C G L I B EnhancerByCGLIB EnhancerByCGLIBdf0ac471 : CGLIB$SET_THREAD_CALLBACKS
在第5步,调用了代理类的CGLIB S E T T H R E A D C A L L B A C K S 来 完 成 拦 截 对 象 的 注 入 。 下 面 看 一 下 C G L I B SET_THREAD_CALLBACKS来完成拦截对象的注入。下面看一下CGLIB SETTHREADCALLBACKS来完成拦截对象的注入。下面看一下CGLIBSET_THREAD_CALLBACKS的反编译结果:
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
在CGLIB S E T T H R E A D C A L L B A C K S 方 法 中 调 用 了 C G L I B SET_THREAD_CALLBACKS方法中调用了CGLIB SETTHREADCALLBACKS方法中调用了CGLIBTHREAD_CALLBACKS的set方法来保存拦截对象,在CGLIB B I N D C A L L B A C K S 方 法 中 使 用 了 C G L I B BIND_CALLBACKS方法中使用了CGLIB BINDCALLBACKS方法中使用了CGLIBTHREAD_CALLBACKS的get方法来获取拦截对象,并保存到CGLIB C A L L B A C K 0 中 。 这 样 , 在 调 用 代 理 类 的 h e l l o 方 法 时 , 就 可 以 获 取 到 我 们 设 置 的 拦 截 对 象 , 然 后 通 过 v a r 10000. i n t e r c e p t ( t h i s , C G L I B CALLBACK_0中。这样,在调用代理类的hello方法时,就可以获取到我们设置的拦截对象,然后通过var10000.intercept(this, CGLIB CALLBACK0中。这样,在调用代理类的hello方法时,就可以获取到我们设置的拦截对象,然后通过var10000.intercept(this,CGLIBhello 0 0 0Method, new Object[]{var1}, CGLIB$hello 0 0 0Proxy)来实现代理。
这里来解释一下intercept方法的参数含义:
@para1 obj:代理对象本身
@para2 method: 被拦截的方法对象
@para3 args:方法调用入参
@para4 proxy:用于调用被拦截方法的方法代理对象
这里会有一个疑问,为什么不直接反射调用代理类生成的(CGLIB$g$0)来间接调用目标类的被拦截方法,而使用proxy的invokeSuper方法呢?这里就涉及到了另外一个点 FastClass 。
FastClass 机制
JDK动态代理的拦截对象是通过反射的机制来调用被拦截方法的,反射的效率比较低,所以CGLIB采用了FastClass机制来实现对被拦截方法的调用。FastClass机制就是对一个类的方法建立索引,通过索引来直接调用相应的方法,下面用一个小例子来说明一下,这样比较直观:
public class FastClass1 {
public void hello(String name) {
System.out.println("hello, " + name);
}
public void hi(String msg) {
System.out.println("hi, " + msg);
}
}
public class FastClass2 {
public Object invoke(Object obj, int methodIndex, Object[] parameters) {
FastClass1 target = (FastClass1)obj;
Object result = null;
switch (methodIndex) {
case 1:
target.hello((String)parameters[0]);
break;
case 2:
target.hi((String)parameters[0]);
break;
}
return result;
}
public int getIndex(String methodDescriptor) {
switch (methodDescriptor.hashCode()) {
case -2084786067:
return 1;
case -70025314:
return 2;
}
return -1;
}
}
public class FastClassTest {
public static void main(String[] args) {
FastClass1 fastClass1 = new FastClass1();
FastClass2 fastClass2 = new FastClass2();
int helloIndex = fastClass2.getIndex("hello(Ljava/lang/String;)V");//方法名(参数类型;...)返回类型
fastClass2.invoke(fastClass1, helloIndex, new Object[]{"张三"});
int hiIndex = fastClass2.getIndex("hi(Ljava/lang/String;)V");
fastClass2.invoke(fastClass1, hiIndex, new Object[]{"cglib动态代理"});
}
}
上例中,FastClass2是FastClass1的Fastclass,在FastClass2中有两个方法getIndex和invoke。在getIndex方法中对FastClass1的每个方法建立索引,并根据入参(方法名+方法的描述符)来返回相应的索引。invoke根据指定的索引,以parameters为入参调用对象obj的方法。这样就避免了反射调用,提高了效率。
代理类(HelloService
E
n
h
a
n
c
e
r
B
y
C
G
L
I
B
EnhancerByCGLIB
EnhancerByCGLIBdf0ac47)中与生成Fastclass相关的代码如下:
Class var0 = Class.forName("cglib.HelloService$$EnhancerByCGLIB$$df0ac471");
var1 = Class.forName("cglib.HelloService");
CGLIB$hello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "hello", "CGLIB$hello$0");
来看下MethodProxy.create方法:
//5个参数分别是
//Class c1 目标类Class
//Class c2 代理类Class
//String desc 代理方法的描述: (参数类型)返回值类型,因为描述中没有方法名,因此这里代理方法描述和被代理方法描述一致
//String name1 被代理方法名
//String 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;
}
MethodProxy.create中会对var0和var1进行分析并生成FastClass,然后再使用getIndex来获取方法hello和CGLIB$hello$0的索引,具体的生成过程将在后续进行介绍,这里介绍一个关键的内部类:
private static class FastClassInfo
{
FastClass f1; //真实类的FastClass
FastClass f2; //代理类的FastClass
int i1; //真实方法的f1的索引
int i2; //代理方法的f2的索引
}
MethodProxy中invokeSuper方法的代码如下:
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();
}
}
private void init()
{
/*
* Using a volatile invariant allows us to initialize the FastClass and
* method index pairs atomically.
*
* 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);
fci.i1 = fci.f1.getIndex(sig1);
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
}
}
}
private static FastClass helper(CreateInfo ci, Class type) {
FastClass.Generator g = new FastClass.Generator();
g.setType(type);
g.setClassLoader(ci.c2.getClassLoader());
g.setNamingPolicy(ci.namingPolicy);
g.setStrategy(ci.strategy);
g.setAttemptLoad(ci.attemptLoad);
return g.create();
}
可以看到FastClass生成调用链:
- MethodProxy : invokeSuper(Object obj, Object[] args)
- MethodProxy : init()
- MethodProxy : helper(CreateInfo ci, Class type)
- FastClass.Generator : create()
而invokeSuper()方法是在代理类方法调用时才会调用,因此FastClass的生成也采用了类似 lazy-init 的方式提高性能。
在MethodProxy.invokeSuper(Object, Object[])中调用了fci.f2.invoke(fci.i2, obj, args)方法,即代理类FastClass的invoke方法,我们来看下代理类FastClass(每个FastClass都有一个Class类生成,我们配置了Class文件生成,反编译):
package cglib;
import cglib.HelloService..EnhancerByCGLIB..df0ac471;
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$$df0ac471$$FastClassByCGLIB$$81065074 extends FastClass {
public HelloService$$EnhancerByCGLIB$$df0ac471$$FastClassByCGLIB$$81065074(Class var1) {
super(var1);
}
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -2071771415:
if(var10000.equals("CGLIB$clone$6()Ljava/lang/Object;")) {
return 22;
}
break;
case -2055565910:
if(var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 13;
}
break;
case -1725733088:
if(var10000.equals("getClass()Ljava/lang/Class;")) {
return 26;
}
break;
case -1663710620:
if(var10000.equals("CGLIB$equals$3(Ljava/lang/Object;)Z")) {
return 19;
}
break;
case -1457535688:
if(var10000.equals("CGLIB$STATICHOOK1()V")) {
return 15;
}
break;
case -1411783143:
if(var10000.equals("CGLIB$hashCode$5()I")) {
return 21;
}
break;
case -1408744366:
if(var10000.equals("CGLIB$hi$1(Ljava/lang/String;)Ljava/lang/String;")) {
return 17;
}
break;
case -1090657086:
if(var10000.equals("hi(Ljava/lang/String;)Ljava/lang/String;")) {
return 7;
}
break;
case -1026001249:
if(var10000.equals("wait(JI)V")) {
return 24;
}
break;
case -894172689:
if(var10000.equals("newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 4;
}
break;
case -879968516:
if(var10000.equals("CGLIB$hello$0(Ljava/lang/String;)Ljava/lang/String;")) {
return 16;
}
break;
case -623122092:
if(var10000.equals("CGLIB$findMethodProxy(Lnet/sf/cglib/core/Signature;)Lnet/sf/cglib/proxy/MethodProxy;")) {
return 14;
}
break;
case -419626537:
if(var10000.equals("setCallbacks([Lnet/sf/cglib/proxy/Callback;)V")) {
return 9;
}
break;
case 243996900:
if(var10000.equals("wait(J)V")) {
return 25;
}
break;
case 560567118:
if(var10000.equals("setCallback(ILnet/sf/cglib/proxy/Callback;)V")) {
return 8;
}
break;
case 811063227:
if(var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 5;
}
break;
case 848333779:
if(var10000.equals("hello(Ljava/lang/String;)Ljava/lang/String;")) {
return 6;
}
break;
case 946854621:
if(var10000.equals("notifyAll()V")) {
return 28;
}
break;
case 973717575:
if(var10000.equals("getCallbacks()[Lnet/sf/cglib/proxy/Callback;")) {
return 11;
}
break;
case 1116248544:
if(var10000.equals("wait()V")) {
return 23;
}
break;
case 1221173700:
if(var10000.equals("newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 3;
}
break;
case 1230699260:
if(var10000.equals("getCallback(I)Lnet/sf/cglib/proxy/Callback;")) {
return 10;
}
break;
case 1365107430:
if(var10000.equals("CGLIB$finalize$2()V")) {
return 18;
}
break;
case 1584330438:
if(var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 12;
}
break;
case 1729170762:
if(var10000.equals("CGLIB$toString$4()Ljava/lang/String;")) {
return 20;
}
break;
case 1826985398:
if(var10000.equals("equals(Ljava/lang/Object;)Z")) {
return 0;
}
break;
case 1902039948:
if(var10000.equals("notify()V")) {
return 27;
}
break;
case 1913648695:
if(var10000.equals("toString()Ljava/lang/String;")) {
return 1;
}
break;
case 1984935277:
if(var10000.equals("hashCode()I")) {
return 2;
}
}
return -1;
}
public int getIndex(String var1, Class[] var2) {
switch(var1.hashCode()) {
case -2083498449:
if(var1.equals("CGLIB$finalize$2")) {
switch(var2.length) {
case 0:
return 18;
}
}
break;
case -1776922004:
if(var1.equals("toString")) {
switch(var2.length) {
case 0:
return 1;
}
}
break;
case -1295482945:
if(var1.equals("equals")) {
switch(var2.length) {
case 1:
if(var2[0].getName().equals("java.lang.Object")) {
return 0;
}
}
}
break;
case -1053468136:
if(var1.equals("getCallbacks")) {
switch(var2.length) {
case 0:
return 11;
}
}
break;
case -1039689911:
if(var1.equals("notify")) {
switch(var2.length) {
case 0:
return 27;
}
}
break;
case -124978607:
if(var1.equals("CGLIB$equals$3")) {
switch(var2.length) {
case 1:
if(var2[0].getName().equals("java.lang.Object")) {
return 19;
}
}
}
break;
case -60403779:
if(var1.equals("CGLIB$SET_STATIC_CALLBACKS")) {
switch(var2.length) {
case 1:
if(var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 12;
}
}
}
break;
case -29025553:
if(var1.equals("CGLIB$hashCode$5")) {
switch(var2.length) {
case 0:
return 21;
}
}
break;
case 3329:
if(var1.equals("hi")) {
switch(var2.length) {
case 1:
if(var2[0].getName().equals("java.lang.String")) {
return 7;
}
}
}
break;
case 3641717:
if(var1.equals("wait")) {
switch(var2.length) {
case 0:
return 23;
case 1:
if(var2[0].getName().equals("long")) {
return 25;
}
break;
case 2:
if(var2[0].getName().equals("long") && var2[1].getName().equals("int")) {
return 24;
}
}
}
break;
case 85179481:
if(var1.equals("CGLIB$SET_THREAD_CALLBACKS")) {
switch(var2.length) {
case 1:
if(var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 13;
}
}
}
break;
case 99162322:
if(var1.equals("hello")) {
switch(var2.length) {
case 1:
if(var2[0].getName().equals("java.lang.String")) {
return 6;
}
}
}
break;
case 147696667:
if(var1.equals("hashCode")) {
switch(var2.length) {
case 0:
return 2;
}
}
break;
case 161998109:
if(var1.equals("CGLIB$STATICHOOK1")) {
switch(var2.length) {
case 0:
return 15;
}
}
break;
case 495524492:
if(var1.equals("setCallbacks")) {
switch(var2.length) {
case 1:
if(var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 9;
}
}
}
break;
case 1154623345:
if(var1.equals("CGLIB$findMethodProxy")) {
switch(var2.length) {
case 1:
if(var2[0].getName().equals("net.sf.cglib.core.Signature")) {
return 14;
}
}
}
break;
case 1543336191:
if(var1.equals("CGLIB$toString$4")) {
switch(var2.length) {
case 0:
return 20;
}
}
break;
case 1811874389:
if(var1.equals("newInstance")) {
switch(var2.length) {
case 1:
String var10001 = var2[0].getName();
switch(var10001.hashCode()) {
case -845341380:
if(var10001.equals("net.sf.cglib.proxy.Callback")) {
return 4;
}
break;
case 1730110032:
if(var10001.equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 3;
}
}
case 2:
default:
break;
case 3:
if(var2[0].getName().equals("[Ljava.lang.Class;") && var2[1].getName().equals("[Ljava.lang.Object;") && var2[2].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 5;
}
}
}
break;
case 1817099975:
if(var1.equals("setCallback")) {
switch(var2.length) {
case 2:
if(var2[0].getName().equals("int") && var2[1].getName().equals("net.sf.cglib.proxy.Callback")) {
return 8;
}
}
}
break;
case 1837078673:
if(var1.equals("CGLIB$hi$1")) {
switch(var2.length) {
case 1:
if(var2[0].getName().equals("java.lang.String")) {
return 17;
}
}
}
break;
case 1891304123:
if(var1.equals("CGLIB$hello$0")) {
switch(var2.length) {
case 1:
if(var2[0].getName().equals("java.lang.String")) {
return 16;
}
}
}
break;
case 1902066072:
if(var1.equals("notifyAll")) {
switch(var2.length) {
case 0:
return 28;
}
}
break;
case 1905679803:
if(var1.equals("getCallback")) {
switch(var2.length) {
case 1:
if(var2[0].getName().equals("int")) {
return 10;
}
}
}
break;
case 1950568386:
if(var1.equals("getClass")) {
switch(var2.length) {
case 0:
return 26;
}
}
break;
case 1951977612:
if(var1.equals("CGLIB$clone$6")) {
switch(var2.length) {
case 0:
return 22;
}
}
}
return -1;
}
public int getIndex(Class[] var1) {
switch(var1.length) {
case 0:
return 0;
default:
return -1;
}
}
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
df0ac471 var10000 = (df0ac471)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
return new Boolean(var10000.equals(var3[0]));
case 1:
return var10000.toString();
case 2:
return new Integer(var10000.hashCode());
case 3:
return var10000.newInstance((Callback[])var3[0]);
case 4:
return var10000.newInstance((Callback)var3[0]);
case 5:
return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
case 6:
return var10000.hello((String)var3[0]);
case 7:
return var10000.hi((String)var3[0]);
case 8:
var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
return null;
case 9:
var10000.setCallbacks((Callback[])var3[0]);
return null;
case 10:
return var10000.getCallback(((Number)var3[0]).intValue());
case 11:
return var10000.getCallbacks();
case 12:
df0ac471.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
return null;
case 13:
df0ac471.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
return null;
case 14:
return df0ac471.CGLIB$findMethodProxy((Signature)var3[0]);
case 15:
df0ac471.CGLIB$STATICHOOK1();
return null;
case 16:
return var10000.CGLIB$hello$0((String)var3[0]);
case 17:
return var10000.CGLIB$hi$1((String)var3[0]);
case 18:
var10000.CGLIB$finalize$2();
return null;
case 19:
return new Boolean(var10000.CGLIB$equals$3(var3[0]));
case 20:
return var10000.CGLIB$toString$4();
case 21:
return new Integer(var10000.CGLIB$hashCode$5());
case 22:
return var10000.CGLIB$clone$6();
case 23:
var10000.wait();
return null;
case 24:
var10000.wait(((Number)var3[0]).longValue(), ((Number)var3[1]).intValue());
return null;
case 25:
var10000.wait(((Number)var3[0]).longValue());
return null;
case 26:
return var10000.getClass();
case 27:
var10000.notify();
return null;
case 28:
var10000.notifyAll();
return null;
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
df0ac471 var10000 = new df0ac471;
df0ac471 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 28;
}
}
代理类FastClass类内容较为丰富,但是结构较为简单,主要提供了以下几个方法:
public int getIndex(Signature var1);
public int getIndex(String var1, Class[] var2);
public int getIndex(Class[] var1);
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException;
public Object newInstance(int var1, Object[] var2) throws InvocationTargetException;
public int getMaxIndex();
在MethodProxy.init()中我们看到FastClassInfo的i1和i2域值的来源:
fci.i1 = fci.f1.getIndex(sig1); //sig1存储目标类的方法信息
fci.i2 = fci.f2.getIndex(sig2);//sig2存储代理类的方法信息
仔细看下代理类FastClass类的getIndex方法:
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -2071771415:
if(var10000.equals("CGLIB$clone$6()Ljava/lang/Object;")) {
return 22;
}
break;
case -2055565910:
if(var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 13;
}
break;
case -1725733088:
if(var10000.equals("getClass()Ljava/lang/Class;")) {
return 26;
}
break;
case -1663710620:
if(var10000.equals("CGLIB$equals$3(Ljava/lang/Object;)Z")) {
return 19;
}
break;
case -1457535688:
if(var10000.equals("CGLIB$STATICHOOK1()V")) {
return 15;
}
break;
case -1411783143:
if(var10000.equals("CGLIB$hashCode$5()I")) {
return 21;
}
break;
case -1408744366:
if(var10000.equals("CGLIB$hi$1(Ljava/lang/String;)Ljava/lang/String;")) {
return 17;
}
break;
case -1090657086:
if(var10000.equals("hi(Ljava/lang/String;)Ljava/lang/String;")) {
return 7;
}
break;
case -1026001249:
if(var10000.equals("wait(JI)V")) {
return 24;
}
break;
case -894172689:
if(var10000.equals("newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 4;
}
break;
case -879968516:
if(var10000.equals("CGLIB$hello$0(Ljava/lang/String;)Ljava/lang/String;")) {
return 16;
}
break;
case -623122092:
if(var10000.equals("CGLIB$findMethodProxy(Lnet/sf/cglib/core/Signature;)Lnet/sf/cglib/proxy/MethodProxy;")) {
return 14;
}
break;
case -419626537:
if(var10000.equals("setCallbacks([Lnet/sf/cglib/proxy/Callback;)V")) {
return 9;
}
break;
case 243996900:
if(var10000.equals("wait(J)V")) {
return 25;
}
break;
case 560567118:
if(var10000.equals("setCallback(ILnet/sf/cglib/proxy/Callback;)V")) {
return 8;
}
break;
case 811063227:
if(var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 5;
}
break;
case 848333779:
if(var10000.equals("hello(Ljava/lang/String;)Ljava/lang/String;")) {
return 6;
}
break;
case 946854621:
if(var10000.equals("notifyAll()V")) {
return 28;
}
break;
case 973717575:
if(var10000.equals("getCallbacks()[Lnet/sf/cglib/proxy/Callback;")) {
return 11;
}
break;
case 1116248544:
if(var10000.equals("wait()V")) {
return 23;
}
break;
case 1221173700:
if(var10000.equals("newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 3;
}
break;
case 1230699260:
if(var10000.equals("getCallback(I)Lnet/sf/cglib/proxy/Callback;")) {
return 10;
}
break;
case 1365107430:
if(var10000.equals("CGLIB$finalize$2()V")) {
return 18;
}
break;
case 1584330438:
if(var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 12;
}
break;
case 1729170762:
if(var10000.equals("CGLIB$toString$4()Ljava/lang/String;")) {
return 20;
}
break;
case 1826985398:
if(var10000.equals("equals(Ljava/lang/Object;)Z")) {
return 0;
}
break;
case 1902039948:
if(var10000.equals("notify()V")) {
return 27;
}
break;
case 1913648695:
if(var10000.equals("toString()Ljava/lang/String;")) {
return 1;
}
break;
case 1984935277:
if(var10000.equals("hashCode()I")) {
return 2;
}
}
return -1;
}
虽然方法长,但逻辑简单。
Signature的toString方法用于返回方法描述:
//在这里就是代理类 CGLIB$hello$0的方法描述 即CGLIB$hello$0(Ljava/lang/String;)Ljava/lang/String;
public String toString() {
return name + desc;
}
可以看到以代理类 CGLIB$hello 0 方 法 为 例 , g e t I n d e x 返 回 方 法 索 引 16 , 即 f c i . i 2 = 16 。 因 此 M e t h o d P r o x y . i n v o k e S u p e r 中 f c i . f 2. i n v o k e ( f c i . i 2 , o b j , a r g s ) ; 即 为 H e l l o S e r v i c e 0方法为例,getIndex返回方法索引16,即fci.i2=16。 因此MethodProxy.invokeSuper中fci.f2.invoke(fci.i2, obj, args);即为HelloService 0方法为例,getIndex返回方法索引16,即fci.i2=16。因此MethodProxy.invokeSuper中fci.f2.invoke(fci.i2,obj,args);即为HelloService E n h a n c e r B y C G L I B EnhancerByCGLIB EnhancerByCGLIB d f 0 a c 471 df0ac471 df0ac471 F a s t C l a s s B y C G L I B FastClassByCGLIB FastClassByCGLIB 81065074. i n v o k e ( 16 , H e l l o S e r v i c e 81065074.invoke(16,HelloService 81065074.invoke(16,HelloService E n h a n c e r B y C G L I B EnhancerByCGLIB EnhancerByCGLIB$df0ac471, [“张三”])。
来看看代理类FastClass的invoke方法:
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
df0ac471 var10000 = (df0ac471)var2; //df0ac471就是代理类
int var10001 = var1; //代理类hello的代理方法CGLIB$hello$0索引 16
try {
switch(var10001) {
case 0:
return new Boolean(var10000.equals(var3[0]));
case 1:
return var10000.toString();
case 2:
return new Integer(var10000.hashCode());
case 3:
return var10000.newInstance((Callback[])var3[0]);
case 4:
return var10000.newInstance((Callback)var3[0]);
case 5:
return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
case 6:
return var10000.hello((String)var3[0]);
case 7:
return var10000.hi((String)var3[0]);
case 8:
var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
return null;
case 9:
var10000.setCallbacks((Callback[])var3[0]);
return null;
case 10:
return var10000.getCallback(((Number)var3[0]).intValue());
case 11:
return var10000.getCallbacks();
case 12:
df0ac471.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
return null;
case 13:
df0ac471.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
return null;
case 14:
return df0ac471.CGLIB$findMethodProxy((Signature)var3[0]);
case 15:
df0ac471.CGLIB$STATICHOOK1();
return null;
case 16:
return var10000.CGLIB$hello$0((String)var3[0]); //成功在此调用了代理类的CGLIB$hello$0方法,
case 17:
return var10000.CGLIB$hi$1((String)var3[0]);
case 18:
var10000.CGLIB$finalize$2();
return null;
case 19:
return new Boolean(var10000.CGLIB$equals$3(var3[0]));
case 20:
return var10000.CGLIB$toString$4();
case 21:
return new Integer(var10000.CGLIB$hashCode$5());
case 22:
return var10000.CGLIB$clone$6();
case 23:
var10000.wait();
return null;
case 24:
var10000.wait(((Number)var3[0]).longValue(), ((Number)var3[1]).intValue());
return null;
case 25:
var10000.wait(((Number)var3[0]).longValue());
return null;
case 26:
return var10000.getClass();
case 27:
var10000.notify();
return null;
case 28:
var10000.notifyAll();
return null;
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
而在代理类CGLIB$hello$0方法中直接调用了其父类,也就是目标类的hello方法:
final String CGLIB$hello$0(String var1) {
return super.hello(var1);
}
至此成功调用原目标类方法。
MethodProxy.invoke(Object obj, Object[] args)
上文我们说了MethodProxy.invokeSuper(Object obj, Object[] args)方法。那么MethodProxy.invoke(Object obj, Object[] args)是什么?
先来看看MethodProxy.invoke(Object obj, Object[] args)的实现:
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;
}
}
可以看到和MethodProxy.invokeSuper(Object obj, Object[] args)较为相似,fci.f1引用的是目标类的FastClass,来看看目标类的FastClass类:
package cglib;
import cglib.HelloService;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.reflect.FastClass;
public class HelloService$$FastClassByCGLIB$$37e7b6d0 extends FastClass {
public HelloService$$FastClassByCGLIB$$37e7b6d0(Class var1) {
super(var1);
}
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -1725733088:
if(var10000.equals("getClass()Ljava/lang/Class;")) {
return 8;
}
break;
case -1090657086:
if(var10000.equals("hi(Ljava/lang/String;)Ljava/lang/String;")) {
return 1;
}
break;
case -1026001249:
if(var10000.equals("wait(JI)V")) {
return 3;
}
break;
case 243996900:
if(var10000.equals("wait(J)V")) {
return 4;
}
break;
case 848333779:
if(var10000.equals("hello(Ljava/lang/String;)Ljava/lang/String;")) {
return 0;
}
break;
case 946854621:
if(var10000.equals("notifyAll()V")) {
return 10;
}
break;
case 1116248544:
if(var10000.equals("wait()V")) {
return 2;
}
break;
case 1826985398:
if(var10000.equals("equals(Ljava/lang/Object;)Z")) {
return 5;
}
break;
case 1902039948:
if(var10000.equals("notify()V")) {
return 9;
}
break;
case 1913648695:
if(var10000.equals("toString()Ljava/lang/String;")) {
return 6;
}
break;
case 1984935277:
if(var10000.equals("hashCode()I")) {
return 7;
}
}
return -1;
}
public int getIndex(String var1, Class[] var2) {
switch(var1.hashCode()) {
case -1776922004:
if(var1.equals("toString")) {
switch(var2.length) {
case 0:
return 6;
}
}
break;
case -1295482945:
if(var1.equals("equals")) {
switch(var2.length) {
case 1:
if(var2[0].getName().equals("java.lang.Object")) {
return 5;
}
}
}
break;
case -1039689911:
if(var1.equals("notify")) {
switch(var2.length) {
case 0:
return 9;
}
}
break;
case 3329:
if(var1.equals("hi")) {
switch(var2.length) {
case 1:
if(var2[0].getName().equals("java.lang.String")) {
return 1;
}
}
}
break;
case 3641717:
if(var1.equals("wait")) {
switch(var2.length) {
case 0:
return 2;
case 1:
if(var2[0].getName().equals("long")) {
return 4;
}
break;
case 2:
if(var2[0].getName().equals("long") && var2[1].getName().equals("int")) {
return 3;
}
}
}
break;
case 99162322:
if(var1.equals("hello")) {
switch(var2.length) {
case 1:
if(var2[0].getName().equals("java.lang.String")) {
return 0;
}
}
}
break;
case 147696667:
if(var1.equals("hashCode")) {
switch(var2.length) {
case 0:
return 7;
}
}
break;
case 1902066072:
if(var1.equals("notifyAll")) {
switch(var2.length) {
case 0:
return 10;
}
}
break;
case 1950568386:
if(var1.equals("getClass")) {
switch(var2.length) {
case 0:
return 8;
}
}
}
return -1;
}
public int getIndex(Class[] var1) {
switch(var1.length) {
case 0:
return 0;
default:
return -1;
}
}
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
HelloService var10000 = (HelloService)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
return var10000.hello((String)var3[0]);
case 1:
return var10000.hi((String)var3[0]);
case 2:
var10000.wait();
return null;
case 3:
var10000.wait(((Number)var3[0]).longValue(), ((Number)var3[1]).intValue());
return null;
case 4:
var10000.wait(((Number)var3[0]).longValue());
return null;
case 5:
return new Boolean(var10000.equals(var3[0]));
case 6:
return var10000.toString();
case 7:
return new Integer(var10000.hashCode());
case 8:
return var10000.getClass();
case 9:
var10000.notify();
return null;
case 10:
var10000.notifyAll();
return null;
}
} 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 10;
}
}
同样是FastClass类结构是相似的,抽离出invoke,我们细看:
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
HelloService var10000 = (HelloService)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
return var10000.hello((String)var3[0]);
case 1:
return var10000.hi((String)var3[0]);
case 2:
var10000.wait();
return null;
case 3:
var10000.wait(((Number)var3[0]).longValue(), ((Number)var3[1]).intValue());
return null;
case 4:
var10000.wait(((Number)var3[0]).longValue());
return null;
case 5:
return new Boolean(var10000.equals(var3[0]));
case 6:
return var10000.toString();
case 7:
return new Integer(var10000.hashCode());
case 8:
return var10000.getClass();
case 9:
var10000.notify();
return null;
case 10:
var10000.notifyAll();
return null;
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
这里就会出现死循环。
以目标类hello()方法为例,调用目标类FastClass类invoke(0, HelloService
E
n
h
a
n
c
e
r
B
y
C
G
L
I
B
EnhancerByCGLIB
EnhancerByCGLIBdf0ac471, [”张三“]),注意这里var2仍是代理类(方法拦截器的interceptor()方法参数没变),因此HelloService var10000 = (HelloService)var2;不会出错,接下来匹配到case 0,继续调用代理类的hello()方法,但是此次调用的源头就是用户用代理类调用hello()方法,死循环。
分析CGLIB动态代理碰到的问题
主要是跑demo碰到的问题。
问题1:异常Exception in thread “main” java.lang.NoClassDefFoundError: org/objectweb/asm/Type
没用引入asm-xxx.jar包。
CGLIB底层通过asm框架生成字节码文件。maven能够引入传递依赖,因此只要依赖cglib就行;否则只能手动引入。
问题2
cglib和asm的jar包冲突,适当降低cglib jar包版本,这里从cglib-3.2.8.jar降到cglib-2.2.2.jar。
问题3
方法拦截器为
public class HelloServiceInterceptor implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class<?> clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
System.out.println("动态代理预处理...");
System.out.println("代理类:" + arg0);
System.out.println("被拦截方法:" + arg1.getName());
Object result = arg3.invokeSuper(arg0, arg2);
System.out.println(result);
System.out.println("动态代理后处理...");
return result;
}
}
出现死循环,并且栈溢出:
根据上文分析,已经很容易判断哪里出问题了?
System.out.println(“代理类:” + arg0);这里有问题,这里arg0是代理类,其实这里调用了arg0.toString()方法。因为CGLIB会默认代理Object类的以下方法:
int hashCode();
public boolean equals(Object obj);
protected native Object clone() throws CloneNotSupportedException;
public String toString();
protected void finalize() throws Throwable;
因此,在方法拦截器的intercept方法中调用以上方法,又会通过代理类的该方法重新调用回方法拦截器的intercept方法,造成栈溢出的死循环。
总结
本文基于CGLIB动态代理的一个demo讨论了CGLIB动态代理的基本原理。
- CGLIB动态代理底层通过ASM字节码操纵框架动态生成代理类及其相关类。
- CGLIB动态代理会动态生成3个Class,分别是代理类,代理类的FastClass类,目标类的FastClass类。
- 目标类名 E n h a n c e r B y C G L I B EnhancerByCGLIB EnhancerByCGLIBhashcode 代理类
- 目标类名 F a s t C l a s s B y C G L I B FastClassByCGLIB FastClassByCGLIBhashcode 目标类FastClass类
- 目标类名 E n h a n c e r B y C G L I B EnhancerByCGLIB EnhancerByCGLIBhashcode F a s t C l a s s B y C G L I B FastClassByCGLIB FastClassByCGLIBhashcode 代理类FastClass类
- CGLIB默认会代理Object类的5个方法(hashCode ,equals,clone,toString,finalize)和目标类中非private(代理类会调用父类即目标类的方法,显然private方法不允许在子类调用),非final方法(代理类要重写代理方法,显然final方法不能重写)。
- 代理类继承目标类,重写代理方法,并在代理方法中调用方法拦截器的intercept方法,最终通过FastClass方式调用代理类中与代理方法相对应的方法(CGLIB 代 理 方 法 名 代理方法名 代理方法名x),并在该方法中调用父类的最终方法。
- CGLIB通过FastClass机制加快方法调用速度,以弥补反射调用的不足;
如何通过代理类的代理方法高效率的访问到目标类的实际方法?
通过代理类代理方法的索引(代理方法描述的hashcode)直接定位到代理类中与代理方法相对应的方法,在这个方法中调用了父类及目标类的实际方法。 - FastClass类的生成延迟到用户调用代理类的代理方法时,并通过缓存的方式,保证每个类(就针对3个类生成)只生成一次。
- 代理类Class在Enhancer.create()时生成,并通过
-Dcglib.debugLocation=H:\EclipseWorkspace\proxy-test\bin\cglib
或
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, “H:\EclipseWorkspace\proxy-test\bin\cglib”);
控制3个Class文件的生成。
参考:
深入理解CGLIB动态代理机制
CGLIB(Code Generation Library)详解
cglib源码分析(一): 缓存和KEY
cglib源码分析(二):Class name 生成策略
cglib源码分析(三):Class生成策略
cglib源码分析(四):cglib 动态代理原理分析
代理9 cglib demo分析以及methodProxy与Fastclass源码