前几天使用公司项目,分析到某个代码接口实现类扫包增强型执行,就是使用的cglib动态代理模式,用来实现对日志打印、分布式锁、事务和异步线程池执行的增强。这里的底层原理是怎样,我下文进行表述。
使用maven依赖引入
创建一个maven项目,pom.xml文件引入如下的依赖。
cglib cglib3.2.12
拦截类说明和创建
创建一个拦截器类CglibMethodInterceptor,实现接口net.sf.cglib.proxy.MethodInterceptor,对应的方法如下:
public class CglibMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("<<<<<日志收集开始...>>>>>>>"); Object reuslt = proxy.invokeSuper(obj, args); System.out.println("<<<<<日志收集结束...>>>>>>>"); return reuslt; } }
proxy为代理类,obj为代理对象,args为目标参数。proxy.invokeSuper(obj,args)为执行代理对象的目标方法。method为目标方法。
如果需要使用代理,则编写如下的方法:
public class TestProxy { public static void main(String[] args) { //System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\code"); CglibMethodInterceptor cglibMethodInterceptor = new CglibMethodInterceptor(); Enhancer enhancer = new Enhancer(); // 设置代理类的父类 enhancer.setSuperclass(HelloServiceImpl.class); // 设置回调对象 enhancer.setCallback(cglibMethodInterceptor); // 创建代理对象 HelloService orderService = (HelloServiceImpl) enhancer.create(); orderService.hello(); } }
Enhancer这里要加入回调拦截器,就是通过setCallback方法进行的,被代理类在setSuperclass来传入的。代理对象通过enhancer#create()方法来创建的。这里可以看到cglib动态代理是通过继承法来进行代理的。那这里底层原理是怎样的,下一节可以展示的。
cglib动态代理原理
如图所示,cglib动态代理生成三个类,第一个的父类才是被代理的类,另外两个是cglib包的enhancer和fastClass的子类。当调用被代理类的方法hello时,走如下的代码:
public final void hello() { 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$hellopublic 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(); } }$Method, CGLIB$emptyArgs, CGLIB$helloprivate static class FastClassInfo { FastClass f1; FastClass f2; int i1; int i2; }$Proxy); } else { super.hello(); } }
这里MethodInterceptor 是上面的实现子类,它为null则直接执行被代理类对应的方法,如果不为空则执行对应的intercept方法。而fastClass如何调用对应的代理类呢?那请看下面的代码:
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 { HelloServiceImpl var10000 = (HelloServiceImpl)var2; int var10001 = var1; try { switch(var10001) { case 0: var10000.hello(); 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"); }
Fastclass类的作用是创建索引机制。他的子类就是上面的第二个,对应生成代码如下:
如果index为0,则执行被代理类的hello。从这里可以看出对应的实现不是通过反射而是通过继承。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)