在之前的文章中我们介绍了JDK动态代理的解析,今天我们来剖析一下Cglib的动态代理解析。
按照惯例我们先用一个简单的例子来说明
HelloService被代理类:
public class HelloService { public void hello() { System.out.println("hello!"); } }
事务增强类MethodInterceptor:
public class TransactionIntercepter implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("开启事务!"); Object object = methodProxy.invokeSuper(o, objects); System.out.println("结束事务!"); return object; } }
测试Cglib动态代理:
public class TestCgLib { public static void main(String[] args) { // 填入以下参数可以将动态生成的类 保存到项目中 System.getProperties().put(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, System.getProperty("user.dir")); Enhancer enhancer = new Enhancer(); HelloService proxyHelloService = (HelloService) enhancer.create(HelloService.class, new TransactionIntercepter()); proxyHelloService.hello(); } }
测试结果:
CGLIB debugging enabled, writing to 'C:/Users/valarchie/IdeaProjects/springAnalysis' 开启事务! hello! 结束事务!
在项目的根路径下会出现一个包,包中有三个class文件就是我们刚才生成的代理类
HelloService$$EnhancerByCGLIB$$e574681b$$FastClassByCGLIB$$397d1c8e.class HelloService$$EnhancerByCGLIB$$e574681b.class HelloService$$FastClassByCGLIB$$51d3e798.class
我们先分析代理类是如何生成的,在分析代理类的内部结构和运作机制。
通过分析以上的Cglib代理示例,先通过一个Enhancer对象,通过setSuperclass()方法填入我们需要被代理的HelloService.class类对象,再通过setCallback()方法填入回调的拦截增强器,最后通过enhancer.create()获取代理类的实例对象。
这与JDK的动态代理不一样,JDK动态代理不需要实现生成被代理的HelloService的实例。
具体我们通过分析代码:enhancer.create()方法,通过追踪发现create()方法有多个重载方法,但最终都指向了createHelper()方法中。
private Object createHelper() { if (classOnly ^ (callbacks == null)) { if (classOnly) { throw new IllegalStateException("createClass does not accept callbacks"); } else { throw new IllegalStateException("callbacks are required unless using createClass"); } } if (callbacks == null && callbackTypes == null) { throw new IllegalStateException("Either callbacks or callback types are always required"); } if (callbacks != null && callbackTypes != null) { if (callbacks.length != callbackTypes.length) { throw new IllegalStateException("Lengths of callback and callback types array must be the same"); } for (int i = 0; i < callbacks.length; i++) { // make sure all classes are callbacks CallbackUtils.getGenerator(callbackTypes[i]); if (callbacks[i] == null) { throw new IllegalStateException("Callback cannot be null"); } if (!callbackTypes[i].isAssignableFrom(callbacks[i].getClass())) { throw new IllegalStateException("Callback " + callbacks[i] + " is not assignable to " + callbackTypes[i]); } } } else if (callbacks != null) { callbackTypes = new Class[callbacks.length]; for (int i = 0; i < callbacks.length; i++) { callbackTypes[i] = CallbackUtils.determineType(callbacks[i]); } } else { for (int i = 0; i < callbackTypes.length; i++) { // make sure all classes are callbacks CallbackUtils.getGenerator(callbackTypes[i]); } } if (filter == null) { if (callbackTypes.length > 1) { throw new IllegalStateException("Multiple callback types possible but no filter specified"); } filter = CallbackFilter.ALL_ZERO; } if (superclass != null) { setNamePrefix(superclass.getName()); } else if (interfaces != null) { setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName()); } Object key = KEY_FACTORY.newInstance(superclass, interfaces, filter, callbackTypes, useFactory); return super.create(key); }
在createHelper()方法中,大部分都是校验代码,在最后两句代码中:
Object key = KEY_FACTORY.newInstance(superclass, interfaces, filter, callbackTypes, useFactory); return super.create(key);
通过将生成代理类的所需信息封装到一个key中,并调用父类的create()方法,通过查看源码我们可以发现Enhancer类的父类为AbstractClassGenerator类,接下来我们查看一下AbstractClassGenerator的create方法。
protected Object create(Object key) { try { Object instance = null; synchronized (source) { ClassLoader loader = getClassLoader(); Map cache2 = null; if (useCache) { cache2 = (Map)source.cache.get(loader); if (cache2 != null) { instance = cache2.get(key); } else { cache2 = new HashMap(); cache2.put(NAME_KEY, new HashSet()); source.cache.put(loader, cache2); } } if (instance == null) { this.key = key; byte[] b = strategy.generate(this); String className = ClassNameReader.getClassName(new ClassReader(b)); getClassNameCache(loader).add(className); instance = firstInstance(ReflectUtils.defineClass(className, b, loader)); if (useCache) { cache2.put(key, instance); } return instance; } } return nextInstance(instance); } catch (RuntimeException e) { throw e; } catch (Error e) { throw e; } catch (Exception e) { throw new CodeGenerationException(e); } }
通过分析代码关键在于strategy.generate(this)如何生成代理类的二进制类信息,之后的代码就是通过类加载器载入代理类的二进制类信息来生成实例(往后就不分析了)。
经过总结生成代理类对象如下三步:
生成代理类的二进制字节码文件。
加载二进制字节码文件到JVM,生成class对象。
反射获得实例构造方法,创建代理对象。
在刚才生成的三个代理类中不带FastClass的就是代理类
package com.valarchie.cglib; import com.valarchie.cglib.HelloService; import java.lang.reflect.Method; import org.springframework.cglib.core.ReflectUtils; import org.springframework.cglib.core.Signature; import org.springframework.cglib.proxy.Callback; import org.springframework.cglib.proxy.Factory; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; public class HelloService$$EnhancerByCGLIB$$e574681b 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$hello$0$Method; private static final MethodProxy CGLIB$hello$0$Proxy; private static final Object[] CGLIB$emptyArgs; private static final Method CGLIB$equals$1$Method; private static final MethodProxy CGLIB$equals$1$Proxy; private static final Method CGLIB$toString$2$Method; private static final MethodProxy CGLIB$toString$2$Proxy; private static final Method CGLIB$hashCode$3$Method; private static final MethodProxy CGLIB$hashCode$3$Proxy; private static final Method CGLIB$clone$4$Method; private static final MethodProxy CGLIB$clone$4$Proxy; static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; Class<?> class_ = Class.forName((String)"com.valarchie.cglib.HelloService$$EnhancerByCGLIB$$e574681b"); Class<?> class_2 = Class.forName((String)"java.lang.Object"); Method[] arrmethod = ReflectUtils.findMethods((String[])new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (Method[])class_2.getDeclaredMethods()); CGLIB$equals$1$Method = arrmethod[0]; CGLIB$equals$1$Proxy = MethodProxy.create(class_2, class_, (String)"(Ljava/lang/Object;)Z", (String)"equals", (String)"CGLIB$equals$1"); CGLIB$toString$2$Method = arrmethod[1]; CGLIB$toString$2$Proxy = MethodProxy.create(class_2, class_, (String)"()Ljava/lang/String;", (String)"toString", (String)"CGLIB$toString$2"); CGLIB$hashCode$3$Method = arrmethod[2]; CGLIB$hashCode$3$Proxy = MethodProxy.create(class_2, class_, (String)"()I", (String)"hashCode", (String)"CGLIB$hashCode$3"); CGLIB$clone$4$Method = arrmethod[3]; CGLIB$clone$4$Proxy = MethodProxy.create(class_2, class_, (String)"()Ljava/lang/Object;", (String)"clone", (String)"CGLIB$clone$4"); class_2 = Class.forName((String)"com.valarchie.cglib.HelloService"); CGLIB$hello$0$Method = ReflectUtils.findMethods((String[])new String[]{"hello", "()V"}, (Method[])class_2.getDeclaredMethods())[0]; CGLIB$hello$0$Proxy = MethodProxy.create(class_2, class_, (String)"()V", (String)"hello", (String)"CGLIB$hello$0"); } final void CGLIB$hello$0() { super.hello(); } public final void hello() { MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0; if (methodInterceptor == null) { HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$BIND_CALLBACKS((Object)((Object)this)); methodInterceptor = this.CGLIB$CALLBACK_0; } if (methodInterceptor != null) { Object object = methodInterceptor.intercept((Object)((Object)this), (Method)CGLIB$hello$0$Method, (Object[])CGLIB$emptyArgs, (MethodProxy)CGLIB$hello$0$Proxy); return; } super.hello(); } final boolean CGLIB$equals$1(Object object) { return super.equals((Object)object); } public final boolean equals(Object object) { MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0; if (methodInterceptor == null) { HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$BIND_CALLBACKS((Object)((Object)this)); methodInterceptor = this.CGLIB$CALLBACK_0; } if (methodInterceptor != null) { Object object2 = methodInterceptor.intercept((Object)((Object)this), (Method)CGLIB$equals$1$Method, (Object[])new Object[]{object}, (MethodProxy)CGLIB$equals$1$Proxy); return object2 == null ? false : ((Boolean)object2).booleanValue(); } return super.equals((Object)object); } final String CGLIB$toString$2() { return super.toString(); } public final String toString() { MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0; if (methodInterceptor == null) { HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$BIND_CALLBACKS((Object)((Object)this)); methodInterceptor = this.CGLIB$CALLBACK_0; } if (methodInterceptor != null) { return (String)methodInterceptor.intercept((Object)((Object)this), (Method)CGLIB$toString$2$Method, (Object[])CGLIB$emptyArgs, (MethodProxy)CGLIB$toString$2$Proxy); } return super.toString(); } final int CGLIB$hashCode$3() { return super.hashCode(); } public final int hashCode() { MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0; if (methodInterceptor == null) { HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$BIND_CALLBACKS((Object)((Object)this)); methodInterceptor = this.CGLIB$CALLBACK_0; } if (methodInterceptor != null) { Object object = methodInterceptor.intercept((Object)((Object)this), (Method)CGLIB$hashCode$3$Method, (Object[])CGLIB$emptyArgs, (MethodProxy)CGLIB$hashCode$3$Proxy); return object == null ? 0 : ((Number)object).intValue(); } return super.hashCode(); } final Object CGLIB$clone$4() throws CloneNotSupportedException { return super.clone(); } protected final Object clone() throws CloneNotSupportedException { MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0; if (methodInterceptor == null) { HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$BIND_CALLBACKS((Object)((Object)this)); methodInterceptor = this.CGLIB$CALLBACK_0; } if (methodInterceptor != null) { return methodInterceptor.intercept((Object)((Object)this), (Method)CGLIB$clone$4$Method, (Object[])CGLIB$emptyArgs, (MethodProxy)CGLIB$clone$4$Proxy); } return super.clone(); } public static MethodProxy CGLIB$findMethodProxy(Signature signature) { String string = signature.toString(); switch (string.hashCode()) { case -792725149: { if (!string.equals((Object)"hello()V")) break; return CGLIB$hello$0$Proxy; } case -508378822: { if (!string.equals((Object)"clone()Ljava/lang/Object;")) break; return CGLIB$clone$4$Proxy; } case 1826985398: { if (!string.equals((Object)"equals(Ljava/lang/Object;)Z")) break; return CGLIB$equals$1$Proxy; } case 1913648695: { if (!string.equals((Object)"toString()Ljava/lang/String;")) break; return CGLIB$toString$2$Proxy; } case 1984935277: { if (!string.equals((Object)"hashCode()I")) break; return CGLIB$hashCode$3$Proxy; } } return null; } public HelloService$$EnhancerByCGLIB$$e574681b() { HelloService$$EnhancerByCGLIB$$e574681b helloService$$EnhancerByCGLIB$$e574681b = this; HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$BIND_CALLBACKS((Object)((Object)helloService$$EnhancerByCGLIB$$e574681b)); } public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] arrcallback) { CGLIB$THREAD_CALLBACKS.set(arrcallback); } public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] arrcallback) { CGLIB$STATIC_CALLBACKS = arrcallback; } private static final void CGLIB$BIND_CALLBACKS(Object object) { HelloService$$EnhancerByCGLIB$$e574681b helloService$$EnhancerByCGLIB$$e574681b = (HelloService$$EnhancerByCGLIB$$e574681b)((Object)object); if (!helloService$$EnhancerByCGLIB$$e574681b.CGLIB$BOUND) { helloService$$EnhancerByCGLIB$$e574681b.CGLIB$BOUND = true; Object object2 = CGLIB$THREAD_CALLBACKS.get(); if (object2 != null || (object2 = CGLIB$STATIC_CALLBACKS) != null) { helloService$$EnhancerByCGLIB$$e574681b.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])object2)[0]; } } } public Object newInstance(Callback[] arrcallback) { HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$SET_THREAD_CALLBACKS((Callback[])arrcallback); HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$SET_THREAD_CALLBACKS(null); return new HelloService$$EnhancerByCGLIB$$e574681b(); } public Object newInstance(Callback callback) { HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$SET_THREAD_CALLBACKS((Callback[])new Callback[]{callback}); HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$SET_THREAD_CALLBACKS(null); return new HelloService$$EnhancerByCGLIB$$e574681b(); } /* * Unable to fully structure code * Enabled aggressive block sorting * Lifted jumps to return sites */ public Object newInstance(Class[] var1_1, Object[] var2_2, Callback[] var3_3) { HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3_3); switch (var1_1.length) { case 0: { ** break; } } throw new IllegalArgumentException((String)"Constructor not found"); lbl6: // 1 sources: HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$SET_THREAD_CALLBACKS(null); return new HelloService$$EnhancerByCGLIB$$e574681b(); } public Callback getCallback(int n) { MethodInterceptor methodInterceptor; HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$BIND_CALLBACKS((Object)((Object)this)); switch (n) { case 0: { methodInterceptor = this.CGLIB$CALLBACK_0; break; } default: { methodInterceptor = null; } } return methodInterceptor; } public void setCallback(int n, Callback callback) { switch (n) { case 0: { this.CGLIB$CALLBACK_0 = (MethodInterceptor)callback; break; } } } public Callback[] getCallbacks() { HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$BIND_CALLBACKS((Object)((Object)this)); HelloService$$EnhancerByCGLIB$$e574681b helloService$$EnhancerByCGLIB$$e574681b = this; return new Callback[]{this.CGLIB$CALLBACK_0}; } public void setCallbacks(Callback[] arrcallback) { Callback[] arrcallback2 = arrcallback; Callback[] arrcallback3 = arrcallback2; HelloService$$EnhancerByCGLIB$$e574681b helloService$$EnhancerByCGLIB$$e574681b = this; this.CGLIB$CALLBACK_0 = (MethodInterceptor)arrcallback2[0]; } static { HelloService$$EnhancerByCGLIB$$e574681b.CGLIB$STATICHOOK1(); } }
通过反编译代码可以发现代理类中有生成了很多Method类型的属性存储方法,调用过程类似于JDK动态代理的过程。Cglib的机制包含FastClass机制有兴趣的话,大家可以查阅一下。