此前一直有一个疑惑,那就是为什么CGLIB生成代理类的时候会出现三个class文件,按道理说应该只有一个。
public class GoodsService {
@Test
public void placeOrder() {
System.out.println("place order");
MsgUtil.addMsg("place order");
}
public void place() {
throw new RuntimeException();
}
@Override
public String toString() {
return "GoodsService{}";
}
}
@Test
public void testEnhance() {
// 获取CGLIB生成的字节码
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\Users\\12130\\Desktop\\新建文件夹");
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(GoodsService.class);
enhancer.setCallback(new TransactionInterceptor());
GoodsService goodsService = (GoodsService) enhancer.create();
goodsService.placeOrder();
}
static class TransactionInterceptor implements MethodInterceptor {
/**
* 参数1:代理类对象
* 参数2:被代理的原始方法
* 参数3:方法参数
* 参数4:fastClass机制相关
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("start interceptor");
// 为什么要执行的是invokeSuper,而不是直接invoke?
Object obj = methodProxy.invokeSuper(o, objects);
System.out.println("end interceptor");
return obj;
}
}
代理类分析
在示例代码中我们通过设置DebuggingClassWriter.DEBUG_LOCATION_PROPERTY的属性值来获取cglib生成的代理类
public class GoodsService$$EnhancerByCGLIB$$b08e58d5 extends GoodsService 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;
// 这就是我们的拦截器,因为只添加了一个拦截器,所以这里只有一个
// CGLIB可以添加多个拦截器
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
// 下面的所有Method都是被代理类的Method,其中也包含了被代理类的没有重写的所有父类的方法
private static final Method CGLIB$toString$0$Method;
// MethodProxy与FastClass机制有关,下面会讲
private static final MethodProxy CGLIB$toString$0$Proxy;
// 空参数,一个默认值,当我们的方法没有参数的时候会传递给拦截器
// 不传递空值,这是一种设置思想
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$placeOrder$1$Method;
private static final MethodProxy CGLIB$placeOrder$1$Proxy;
private static final Method CGLIB$place$2$Method;
private static final MethodProxy CGLIB$place$2$Proxy;
private static final Method CGLIB$equals$3$Method;
private static final MethodProxy CGLIB$equals$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("com.cp.v5.service.GoodsService$$EnhancerByCGLIB$$b08e58d5");
Class var1;
// 获取了GoodService的父类的所有的方法,这里因为GoodsService只有一个Object父类
// 如果存在多个父类,这里会有多个加载没有被子类重写的父类的方法
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$3$Method = var10000[0];
// 创建MethodProxy,每一个方法都会有一个对应的MethodProxy
// 了解一下这里传递的参数,var1现在是Object,var0则是当前生成的代理类
// 传入了两个方法来计算方法下标
CGLIB$equals$3$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$3");
CGLIB$hashCode$4$Method = var10000[1];
CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
CGLIB$clone$5$Method = var10000[2];
CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
var10000 = ReflectUtils.findMethods(new String[]{"toString", "()Ljava/lang/String;", "placeOrder", "()V", "place", "()V"}, (var1 = Class.forName("com.cp.v5.service.GoodsService")).getDeclaredMethods());
CGLIB$toString$0$Method = var10000[0];
CGLIB$toString$0$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$0");
CGLIB$placeOrder$1$Method = var10000[1];
CGLIB$placeOrder$1$Proxy = MethodProxy.create(var1, var0, "()V", "placeOrder", "CGLIB$placeOrder$1");
CGLIB$place$2$Method = var10000[2];
CGLIB$place$2$Proxy = MethodProxy.create(var1, var0, "()V", "place", "CGLIB$place$2");
}
/**
* 用来调用父类的原始方法
* CGLIB生成代理利用的是继承,而不是JDK动态代理的利用接口的形式
* 这样就有一个区别就出现了,JDK动态代理中必须要有一个被代理类的实例
* 但是CGLIB实现的动态代理就不需要,因为是继承,所以就包含了被代理类的全部方法
* 但是就像下面一样,toString()方法被重写了,所以需要生成当前方法来调用父类的方法
*/
final String CGLIB$toString$0() {
return super.toString();
}
/**
* 生成的代理方法,在该方法中会调用我们设置的Callback
* 当调用代理类的toString方法时,先判断是否已经存在实现了MethodInterceptor接口的拦截对象
* 如果没有的话就调用CGLIB$BIND_CALLBACKS方法来获取拦截对象
*/
public final String toString() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$0$Method, CGLIB$emptyArgs, CGLIB$toString$0$Proxy) : super.toString();
}
/**
* 删除了生成的其他代理方法,被代理类中的,每一个方法都会生成上面这种形式的两个方法
* 还有几个newInstance()方法,newInstance()方法来源于Factory接口
* 从上面可以看到生成的代理类实现了Factory接口
*/
public GoodsService$$EnhancerByCGLIB$$b08e58d5() {
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;
}
/**
* CGLIB$BIND_CALLBACKS 先从CGLIB$THREAD_CALLBACKS中get拦截对象
* 如果获取不到的话,再从CGLIB$STATIC_CALLBACKS来获取,如果也没有则认为该方法不需要代理。
* 那么拦截对象是如何设置到CGLIB$THREAD_CALLBACKS 或者 CGLIB$STATIC_CALLBACKS中的呢?
* 在Jdk动态代理中拦截对象是在实例化代理类时由构造函数传入的
* 在cglib中我们使用Enhancers生成代理类时。是调用Enhancer的firstInstance方法来生成代理类实例并设置拦截对象的。
* firstInstance的调用轨迹为:
1.Enhancer:firstInstance
2.Enhancer:createUsingReflection
3.Enhancer:setThreadCallbacks
4.Enhancer:setCallbacksHelper
5.Target$$EnhancerByCGLIB$$788444a0 : CGLIB$SET_THREAD_CALLBACKS
* 最终实例化代理对象的时候,就在这里将所有的Callback成功设置了
*/
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
GoodsService$$EnhancerByCGLIB$$b08e58d5 var1 = (GoodsService$$EnhancerByCGLIB$$b08e58d5)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];
}
}
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();
}
}
FastClass
Jdk动态代理的拦截对象是通过反射的机制来调用被拦截实例方法的,反射的效率比较低,所以cglib采用了FastClass的机制来实现对被拦截方法的调用。FastClass机制就是对一个类的方法建立索引,调用方法时根据方法的签名来计算索引,通过索引来直接调用相应的方法。
这也就是为什么CGLIB生成的动态代理会包含3个class文件的原因,其中一个是生成的代理类,另外两个类都是FastClass机制需要的,另外两个类都继承了FastClass这个类。其中一个是实现被代理类的FastClass机制,另外一个是实现代理类的FastClass机制。
在上面生成的代理类中能看到MethodProxy,FastClass就是在该类中生成的
这就是GoodService类生成的对应的FastClass类
public class GoodsService$$FastClassByCGLIB$$58067f53 extends FastClass {
public GoodsService$$FastClassByCGLIB$$58067f53(Class var1) {
super(var1);
}
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case 1203662734:
if (var10000.equals("placeOrder()V")) {
return 1;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return 3;
}
break;
case 1858883854:
if (var10000.equals("place()V")) {
return 2;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return 0;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return 4;
}
}
return -1;
}
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
GoodsService var10000 = (GoodsService)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
return var10000.toString();
case 1:
var10000.placeOrder();
return null;
case 2:
var10000.place();
return null;
case 3:
return new Boolean(var10000.equals(var3[0]));
case 4:
return new Integer(var10000.hashCode());
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
}
我们上面代理类中执行的create(),将类和方法信息保存了起来
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;
}
我们在Callback中执行MethodProxy的invokeSuper方法
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
// 调用init方法,就是获取方法下标,且要生成FastClass类
init();
FastClassInfo fci = fastClassInfo;
// f2是被代理类,所以这里是执行被代理类下标为i2的方法
// 假设我们调用的上面的toString()方法,其实也就是调用的代理类的CGLIB$toString$0方法,这样就实现了原始方法的调用,所以我们才需要执行invokeSuper
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
/**
* 在相同类型的不同对象上调用原始方法
* 什么意思呢?CGLIB也可以针对接口实现动态代理
* 接口实现的动态代理就需要传入一个被代理的实例,然后利用该方法来执行被代理实例的方法
* 而不是使用上面的invokeSuper
* 综合所有的代码我们可以看出:
* invokeSuper是执行生成的代理类的方法,因为f2这个FastClass是代理类的FastClass
* invoke执行的是原始类的方法,因为f1
*/
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;
}
}
private static class FastClassInfo
{
// 被代理类的FastClass
FastClass f1;
// 代理类的FastClass
FastClass f2;
int i1;
int i2;
}
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();
// helper中生成了对应Class的FastClass,这里可以看出就是生成了两个Class的FastClass
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;
}
}
}
}