public class MyService { public void print(){ System.out.println("this is print!"); } } 复制代码
public class CglibIntercepter implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("this is before!"); Object result = proxy.invokeSuper(obj, args); System.out.println("this is after!"); return result; } } 复制代码
public class CglibDemo { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(MyService.class); enhancer.setCallback(new CglibIntercepter()); MyService service = (MyService) enhancer.create(); service.print(); } } 复制代码
不出意外的话,控制台会打印
this is before! this is print! this is after! 复制代码
这说明我们的方法得到了增强。
如果已经看过jdk的动态代理这篇文章的话,那你对cglib动态代理应该也是有一点想法的。他们实现的手段相似,都是通过字节码技术来生成新类。
所以新类生成的地方我就不带着找了。根据方法参数和返回值很容易分析到。直接来看一下cglib生成的新类吧。
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"d:/cglib"); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(MyService.class); enhancer.setCallback(new CglibIntercepter()); MyService service = (MyService) enhancer.create(); service.print(); 复制代码
在测试代码最上面增加一行,设置cglib将新类的class文件打印的地方。设置好了运行一遍,不出意外可以在d盘的cglib文件夹中找到D:/cglib*/*/cglib_proxy这个文件夹,里面有三个类。一个继承自MyService,两个继承自fastclass, 首先来看一下继承自MyService的这个类。
不用猜也知道,这个就是cglib增强后的类了。所以找关键代码。
public final void print() { 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$print$0$Method, CGLIB$emptyArgs, CGLIB$print$0$Proxy); } else { super.print(); } } 复制代码
当我们调用了print方法后,其实是调用的var10000.intercept()方法,var10000你可能有点陌生,MethodInterceptor但是这个应该认识吧。这个就是我们用来创建拦截器的接口。而这边的var10000,其实就是我们创建的那个拦截器。
所以拦截器如何增强方法到这边应该清楚了,下面就跟踪一下MethodProxy的invokeSuper方法。
首先通过静态代码块得知MethodProxy的来源
CGLIB$print$0$Proxy = MethodProxy.create(var1, var0, "()V", "print", "CGLIB$print$0"); 复制代码
var1代表着原来的类,var0代表新类,跟踪进入
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; } 复制代码
只是做了些标记,搞清楚标记的顺序后,开始分析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(); } } 复制代码
CreateInfo ci = createInfo; FastClassInfo fci = new FastClassInfo(); 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; 复制代码
init方法关键点,f1和f2分别是啥?i1 和i2又分别是啥?进入helper方法
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); 复制代码
FastClass.Generator和我们用来增强类的Enhancer类一样,都继承自AbstractClassGenerator类,而这边调用了create方法,显然也是生成了一个新类,那这个新类在哪里呢?
还记得一开始在文件夹中的另外两个类么,其实他们就是这边生成的fastclass类。打开那两个类,进入getIndex方法
public int getIndex(Signature var1) { String var10000 = var1.toString(); switch(var10000.hashCode()) { case -1166389848: if (var10000.equals("print()V")) { return 0; } break; case 1826985398: if (var10000.equals("equals(Ljava/lang/Object;)Z")) { return 1; } break; case 1913648695: if (var10000.equals("toString()Ljava/lang/String;")) { return 2; } break; case 1984935277: if (var10000.equals("hashCode()I")) { return 3; } } return -1; } 复制代码
逻辑很简单,就算根据方法的hash吗,返回int标志。所以到这儿f1,f2,fci.i1,fci.i2就都应该知道是啥含义了。
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException { MyService var10000 = (MyService)var2; int var10001 = var1; try { switch(var10001) { case 0: var10000.print(); return null; case 1: return new Boolean(var10000.equals(var3[0])); case 2: return var10000.toString(); case 3: return new Integer(var10000.hashCode()); } } catch (Throwable var4) { throw new InvocationTargetException(var4); } throw new IllegalArgumentException("Cannot find matching method/constructor"); } 复制代码
其实我觉得到这儿已经没啥好说的了,先在init方法中,获得每个方法的标志,在拿着标志去执行invoke方法。不同的标志执行不同的方法,就这样。
需要注意的是,jdk动态代理,执行方法是通过反射执行的,而cglib动态代理,是通过标志区分,直接执行原类的方法,所以效率更高。