JDK动态代理与CGLIB动态代理应用及源码解析
2018-03-15 13:40
716 查看
代理模式
代理模式:为其他对象提供一种代理以控制对这个对象的访问。代理模式中有三种角色:Subject抽象主题角色、RealSubject真实主题角色、Proxy代理主题角色。Subject描述了业务行为,RealSubject执行具体的业务逻辑,Proxy代理会拦截对RealSubject对象方法的调用,并在方法调用前后做预处理以及一些善后工作。
代理模式可以很好地在不侵入原代码的情况下,拓展原来的功能。
下图为Proxy模式的静态类图:
下图为Proxy模式的调用关系:
动态代理
静态代理由于硬编码,难以应对真实对象和调用方法灵活多变的情况,动态代理则对这些场景应付自如。动态代理主要有两种实现方式:1、JDK自带的Proxy 2、CGLIB字节码生成库
基于JDK的动态代理
基于JDK的动态代理关键在于两个类:InvocationHandler和Proxy。其主要实现逻辑是,由InvocationHandler定义方法执行前后的增强逻辑,由Proxy类去生成一个继承自Proxy并且实现了真实对象接口的新对象–代理对象,对该代理对象的方法调用经由InvocationHandler拦截,执行增强逻辑和调用真实对象执行业务逻辑。
下面我们先看一个例子:
定义接口:
public interface UserService { public String getName(int id); public Integer getAge(int id); }
定义真实对象:
public class UserServiceImpl implements UserService { public UserServiceImpl() { } @Override public String getName(int id) { System.out.println("---getName---"); return "John"; } @Override public Integer getAge(int id) { System.out.println("---getAge---"); return 10; } }
定义InvocationHandler:
public class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("getName")) { System.out.println("+++before get name+++"); Object res = method.invoke(target, args); System.out.println("+++after get name+++"); return res; } else { Object res = method.invoke(target, args); return res; } } public static void main(String[] args) { System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); UserService us = new UserServiceImpl(); InvocationHandler ih = new MyInvocationHandler(us); UserService usProxy = (UserService) Proxy.newProxyInstance(us.getClass().getClassLoader(), us.getClass().getInterfaces(), ih); System.out.println(usProxy.getName(1)); System.out.println(usProxy.getAge(1)); System.out.println(usProxy.getClass()); } }
测试结果:
可以看到,对于getName方法的增强逻辑执行了。
下面我们从源码角度分析一下这个过程的实现原理,先看InvocationHandler:
InvocationHandler是一个接口,只有一个方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
在定义增强逻辑类时,需要实现该接口,并在invoke方法里实现增强逻辑和对真实对象方法的调用。对于invoke方法的三个参数,proxy表示代理对象,method表示真实对象的方法,args表示真实对象方法的参数,这里也可以看出对真实对象方法的调用是通过反射来实现的。
增强逻辑定义好了以后,我们需要一个代理对象来执行,先看如何产生这个代理对象。代理对象的产生是通过调用Proxy类的静态方法:newProxyInstance,以下源码分析部分篇幅原因仅截取部分代码片段。
public static Object newProxyInst 4000 ance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException //该方法需要三个参数:ClassLoader确保返回的代理对象和真实对象由同一个类 加载器加载,interfaces用于定义代理类应该实现的方法, invocationHandler用于定义代理类的增强逻辑 { if (h == null) { throw new NullPointerException(); } final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ //这一行代码很关键,这里是获取代理对象Class对象,Proxy类内部维护了代理 //对象的缓存,如果缓存里有则直接返回,如果没有,则生成它 Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { //由Class对象获取构造器 final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { // create proxy instance with doPrivilege as the proxy class may // implement non-public interfaces that requires a special permission return AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { return newInstance(cons, ih); } }); } else { //最后由构造器返回新的代理对象实例 return newInstance(cons, ih); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } }
接下来我们看代理对象的Class对象是如何生成的,缓存逻辑略去不表,直接看没有缓存的情况,代理类Class对象由ProxyClassFactory工厂生成:
private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // prefix for all proxy class names private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names private static final AtomicLong nextUniqueNumber = new AtomicLong(); //验证代码略去 /* * Generate the specified proxy class. */ //这里生成了代理对象二进制字节码流 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces); try { //通过二进制字节码流加载代理类 return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { throw new IllegalArgumentException(e.toString()); } } }
最终生成二进制字节码流用到了Sun的ProxyGenerator类,反编译:
public static byte[] generateProxyClass(String s, Class aclass[]) { ProxyGenerator proxygenerator = new ProxyGenerator(s, aclass); //该方法生成代理对象的二进制字节码流 byte abyte0[] = proxygenerator.generateClassFile(); //如果要保存该字节码文件,可以将其写到硬盘上,我们稍后分析 if(saveGeneratedFiles) //保存文件部分略去 return abyte0; }
具体生成源码如下:
private byte[] generateClassFile() { addProxyMethod(hashCodeMethod, java / lang / Object); addProxyMethod(equalsMethod, java / lang / Object); addProxyMethod(toStringMethod, java / lang / Object); for (int i = 0; i < interfaces.length; i++) { Method amethod[] = interfaces[i].getMethods(); for (int k = 0; k < amethod.length; k++) addProxyMethod(amethod[k], interfaces[i]); } List list; for (Iterator iterator = proxyMethods.values().iterator(); iterator.hasNext(); checkReturnTypes(list)) list = (List) iterator.next(); try { methods.add(generateConstructor()); for (Iterator iterator1 = proxyMethods.values().iterator(); iterator1.hasNext();) { List list1 = (List) iterator1.next(); Iterator iterator2 = list1.iterator(); while (iterator2.hasNext()) { ProxyMethod proxymethod = (ProxyMethod) iterator2.next(); fields.add(new FieldInfo(proxymethod.methodFieldName, "Ljava/lang/reflect/Method;", 10)); methods.add(proxymethod.generateMethod()); } } methods.add(generateStaticInitializer()); } catch (IOException ioexception) { throw new InternalError("unexpected I/O Exception"); } if (methods.size() > 65535) throw new IllegalArgumentException("method limit exceeded"); if (fields.size() > 65535) throw new IllegalArgumentException("field limit exceeded"); cp.getClass(dotToSlash(className)); cp.getClass("java/lang/reflect/Proxy"); for (int j = 0; j < interfaces.length; j++) cp.getClass(dotToSlash(interfaces[j].getName())); cp.setReadOnly(); ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(); DataOutputStream dataoutputstream = new DataOutputStream(bytearrayoutputstream); try { dataoutputstream.writeInt(-889275714); dataoutputstream.writeShort(0); dataoutputstream.writeShort(49); cp.write(dataoutputstream); dataoutputstream.writeShort(49); dataoutputstream.writeShort(cp.getClass(dotToSlash(className))); dataoutputstream.writeShort(cp.getClass("java/lang/reflect/Proxy")); dataoutputstream.writeShort(interfaces.length); for (int l = 0; l < interfaces.length; l++) dataoutputstream.writeShort(cp.getClass(dotToSlash(interfaces[l].getName()))); dataoutputstream.writeShort(fields.size()); FieldInfo fieldinfo; for (Iterator iterator3 = fields.iterator(); iterator3.hasNext(); fieldinfo.write(dataoutputstream)) fieldinfo = (FieldInfo) iterator3.next(); dataoutputstream.writeShort(methods.size()); MethodInfo methodinfo; for (Iterator iterator4 = methods.iterator(); iterator4.hasNext(); methodinfo.write(dataoutputstream)) methodinfo = (MethodInfo) iterator4.next(); dataoutputstream.writeShort(0); } catch (IOException ioexception1) { throw new InternalError("unexpected I/O Exception"); } return bytearrayoutputstream.toByteArray(); }
至此,总结一下,Proxy类通过ProxyClassFactory生成了继承Proxy类并实现了真实对象接口的 $ProxyX代理对象的二进制字节码流,并加载该字节码返回代理对象Class对象,由该Class对象经反射得到构造器构造了代理对象的实例。
在源码中我们可以通过saveGeneratedFiles变量保存生成的class文件,我们反编译上面的示例生成的class文件:
public final class $Proxy0 extends Proxy implements UserService { private static Method m1; private static Method m4; private static Method m0; private static Method m3; private static Method m2; public $Proxy0(InvocationHandler invocationhandler) { super(invocationhandler); } public final boolean equals(Object obj) { try { return ((Boolean) super.h.invoke(this, m1, new Object[]{obj})).booleanValue(); } catch (Error _ex) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } //这里是UserService接口的getAge方法,在代理对象$Proxy0上的调用被invocationHandler拦截, //经由其invoke方法调用(即我们之前定义的MyinvocationHandler的invoke方法), //留意invoke方法的参数,我们在MyinvocationHandler里定义invoke方法时并没有使用proxy参数, //这里proxy参数的位置传入了this变量,即代理对象本身。 public final Integer getAge(int i) { try { return (Integer) super.h.invoke(this, m4, new Object[]{Integer.valueOf(i)}); } catch (Error _ex) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final int hashCode() { try { return ((Integer) super.h.invoke(this, m0, null)).intValue(); } catch (Error _ex) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final String getName(int i) { try { return (String) super.h.invoke(this, m3, new Object[]{Integer.valueOf(i)}); } catch (Error _ex) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final String toString() { try { return (String) super.h.invoke(this, m2, null); } catch (Error _ex) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")}); m4 = Class.forName("cn.john.test.dynamicProxy.UserService").getMethod("getAge", new Class[]{Integer.TYPE}); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m3 = Class.forName("cn.john.test.dynamicProxy.UserService").getMethod("getName", new Class[]{Integer.TYPE}); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); } catch (NoSuchMethodException nosuchmethodexception) { throw new NoSuchMethodError(nosuchmethodexception.getMessage()); } catch (ClassNotFoundException classnotfoundexception) { throw new NoClassDefFoundError(classnotfoundexception.getMessage()); } } }
基于CGLIB的动态代理
使用示例
public class UserServiceB { public String getName(int id) { System.out.println("---getName---"); return "John"; } public Integer getAge(int id) { System.out.println("---getAge---"); return 10; } public static void main(String[] args) throws InterruptedException, IOException { //将cglib生成的Class对象写成文件存入硬盘,后面反编译出来用以分析 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class"); UserServiceB us = new UserServiceB(); // 定义增强器 Enhancer en = new Enhancer(); // 定义要代理的对象 en.setSuperclass(us.getClass()); // 定义回调函数 en.setCallback(new MethodInterceptor() { //这里要理解intercept方法的几个参数代表的意思 //obj指的是代理类对象 //Method指的是 目标类中被拦截的方法 //args指的是 调用拦截方法所需的参数 //MethodProxy指的是用来调用目标类被拦截方法的方法,这个方法比反射更快 @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("-----before-------"); //这里只能用invokeSuper,原因稍后解释 methodProxy.invokeSuper(obj, args); System.out.println("-----after--------"); return null; } }); // 生成代理对象 UserServiceB usb = (UserServiceB) en.create(); // 在代理对象上调用方法 usb.getName(1); } }
运行结果:
同时生成了三个class文件:一个是代理类,一个是代理类的FastClass,一个是目标类的FastClass
源码分析
代理类源码概览从上面的示例代码中,我们知道通过cglib生成代理类只需要一个目标类和一个回调函数(增强逻辑),下面我们从在代理对象上调用getName()方法出发,一步一步分析cglib动态代理的实现原理。
先来看生成的代理对象Class文件反编译后的源码(代码很长,代理了Object中的finalize,equals, toString,hashCode,clone方法,这里仅留下getName()方法):
public class UserServiceB$$EnhancerByCGLIB$$a33459ad extends UserServiceB implements Factory { //cglib基于继承,可以看到代理类继承了目标类,并实现了Factory接口,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$getName$0$Method;//目标类的getName方法 private static final MethodProxy CGLIB$getName$0$Proxy;//getName方法的代理方法 //初始化变量 static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; //代理类 Class class_ = Class.forName("cn.john.test.dynamicProxy.UserServiceB$$EnhancerByCGLIB$$a33459ad"); //目标类 Class class_2 = Class.forName("cn.john.test.dynamicProxy.UserServiceB"); Method[] arrmethod = ReflectUtils.findMethods( (String[]) new String[]{"getName", "(I)Ljava/lang/String;", "getAge", "(I)Ljava/lang/Integer;"}, (Method[]) class_2.getDeclaredMethods()); //getName方法 CGLIB$getName$0$Method = arrmethod[0]; //建立更快的方法索引访问方式,这里通过目标类和代理类的Class对象和方法签名为这两个对象 //的所有方法都建立了索引,并提供了通过索引调用的方法。 //这里CGLIB$getName$0$Proxy提供在目标类(或者兼容类)上快速调用getName和在代理类上 //快速调用CGLIB$getName$0的功能 CGLIB$getName$0$Proxy = MethodProxy.create(class_2, class_, (String) "(I)Ljava/lang/String;", (String) "getName", (String) "CGLIB$getName$0"); } //直接调用了目标类的方法,这个方法即用来执行目标类真实逻辑,通过索引调用来快速访问该方法 final String CGLIB$getName$0(int n) { return super.getName(n); } //代理方法getName入口 public final String getName(int n) { //先获取回调函数 MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0; if (methodInterceptor == null) { UserServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$BIND_CALLBACKS((Object) this); methodInterceptor = this.CGLIB$CALLBACK_0; } //获取了回调函数之后 if (methodInterceptor != null) { //调用回调函数的拦截方法。 //注意这里传入的参数,代理类传入的this,被拦截的方法传入的是目标类对象的 //被拦截的方法,methodProxy传入的是getName方法的快速访问代理 return (String) methodInterceptor.intercept((Object) this, CGLIB$getName$0$Method, new Object[]{new Integer(n)}, CGLIB$getName$0$Proxy); } return super.getName(n); } public UserServiceB$$EnhancerByCGLIB$$a33459ad() { UserServiceB$$EnhancerByCGLIB$$a33459ad userServiceB$$EnhancerByCGLIB$$a33459ad = this; UserServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$BIND_CALLBACKS((Object) userServiceB$$EnhancerByCGLIB$$a33459ad); } 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) { UserServiceB$$EnhancerByCGLIB$$a33459ad userServiceB$$EnhancerByCGLIB$$a33459ad = (UserServiceB$$EnhancerByCGLIB$$a33459ad) ((Object) object); if (!userServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$BOUND) { userServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$BOUND = true; Object t = CGLIB$THREAD_CALLBACKS.get(); if (t != null || (v13465 = CGLIB$STATIC_CALLBACKS) != null) { userServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$CALLBACK_0 = (MethodInterceptor) ((Callback[]) t)[0]; } } } static { UserServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$STATICHOOK1(); } }
进入回调函数后,跟JDK动态代理InvocationHandler一样,先执行前置增强逻辑,然后将目标类的真实逻辑。注意此处目标类的真实逻辑执行cglib的实现方式与JDK实现方式不同:JDK使用的是反射技术,而cglib则使用了FastClass构建方法索引+继承的方式访问目标类的方法。
建立getName方法和CGLIB$getName0的索引
CGLIB$getName$0$Proxy = MethodProxy.create(class_2, class_, (String) "(I)Ljava/lang/String;", (String) "getName", (String) "CGLIB$getName$0"); //注意这里class_2是目标类,class_是代理类
我们截取MethodProxy类的部分代码:
private static class CreateInfo { Class c1; Class c2; NamingPolicy namingPolicy; GeneratorStrategy strategy; boolean attemptLoad; public CreateInfo(Class c1, Class c2) { this.c1 = c1; this.c2 = c2; AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent(); if (fromEnhancer != null) { this.namingPolicy = fromEnhancer.getNamingPolicy(); this.strategy = fromEnhancer.getStrategy(); this.attemptLoad = fromEnhancer.getAttemptLoad(); } } } //注意在MethodProxy类内部变量命名:这里目标类为1,而代理类变为了2 public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) { //准备数据阶段,目标类和代理类的Class对象,需要映射的方法签名,这里并不会 //触发实际上的建立方法索引 MethodProxy proxy = new MethodProxy(); proxy.sig1 = new Signature(name1, desc); proxy.sig2 = new Signature(name2, desc); proxy.createInfo = new CreateInfo(c1, c2); return proxy; }
实际建立方法索引发生在回调函数中方法调用时(Lazyinit):
//MethodProxy类中的InvokeSuper public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { this.init();//实际的方法索引在此时建立 FastClassInfo fci = this.fastClassInfo; //在代理类FastClass对象上调用索引为i2的方法 return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } } //内部类FastClassInfo private static class FastClassInfo { FastClass f1;//目标类fc FastClass f2;//代理类fc int i1;//目标类getName方法索引 int i2;//代理类CGLIB$getName$0方法索引 private FastClassInfo() { } } private void init() { if (this.fastClassInfo == null) { Object object = this.initLock; synchronized (object) { if (this.fastClassInfo == null) { CreateInfo ci = this.createInfo; FastClassInfo fci = new FastClassInfo(); //这里通过字节码技术生成目标类和代理类的FastClass类的实例 //FastClass关键有两类方法: //一类是getIndex方法,通过方法签名获取某方法的索引 //一类是invoke方法,通过方法的索引来找到方法并调用 fci.f1 = MethodProxy.helper(ci, ci.c1);//生成目标类的FastClass对象 fci.f2 = MethodProxy.helper(ci, ci.c2);//生成代理类的FastClass对象 //获取目标类和代理类的方法索引 fci.i1 = fci.f1.getIndex(this.sig1); fci.i2 = fci.f2.getIndex(this.sig2); this.fastClassInfo = fci;//至此,getName方法的索引建立、获取完毕 this.createInfo = null; } } } }
回到示例上层代码:
methodProxy.invokeSuper(obj, args);这里obj是代理对象,再看invokeSuper:
public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { init();//建立和获取索引 FastClassInfo fci = fastClassInfo; //在obj即代理对象上调用索引为i2的方法 return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } }
现在我们反编译代理类的FastClass类看一下,
fci.f2.invoke(fci.i2, obj, args);到底意味着什么。
代理类FastClass(部分代码):
public class UserServiceB$$EnhancerByCGLIB$$a33459ad$$FastClassByCGLIB$$9e4fc4c5 extends FastClass { public UserServiceB$$EnhancerByCGLIB$$a33459ad$$FastClassByCGLIB$$9e4fc4c5(Class class_) { super(class_); } public int getIndex(Signature signature) { String string = signature.toString(); switch (string.hashCode()) { case -2024387448 : { //在上面的Init方法中我们已经获取了CGLIB$getName$0的索引,值为18 if (!string.equals("CGLIB$getName$0(I)Ljava/lang/String;")) break; return 18; } case 206620625 : { if (!string.equals("getName(I)Ljava/lang/String;")) break; return 3; } } return -1; } //在代理对象上调用索引为18的方法 public Object invoke(int n, Object object, Object[] arrobject) throws InvocationTargetException { UserServiceB$$EnhancerByCGLIB$$a33459ad userServiceB$$EnhancerByCGLIB$$a33459ad = (UserServiceB$$EnhancerByCGLIB$$a33459ad) ((Object) object); try { switch (n) { case 3 : { return userServiceB$$EnhancerByCGLIB$$a33459ad.getName(((Number) arrobject[0]).intValue()); } //在代理对象上调用了CGLIB$getName$0方法,回到代理类源码,它调用super.getName,即目标类的真实逻辑 case 18 : { return userServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$getName$0(((Number) arrobject[0]).intValue()); } } } catch (Throwable v1) { throw new InvocationTargetException(v1); } throw new IllegalArgumentException("Cannot find matching method/constructor"); } }
现在我们来回答一下为什么示例代码中不能调用invoke,而是只能调用invokeSuper。invoke代码:
public Object invoke(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = fastClassInfo; //因为在回调函数中obj传入的代理对象,这里实际上是在代理对象上调用 //getName方法,将陷入无限递归,直至栈溢出 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; } }
总结
类型 | 机制 | 回调方式 | 适用场景 | 效率 |
---|---|---|---|---|
JDK动态代理 | 委托机制,代理类和目标类都实现了同样的接口,InvocationHandler持有目标类,代理类委托InvocationHandler去调用目标类的原始方法 | 反射 | 目标类是接口类 | 效率瓶颈在反射调用稍慢 |
CGLIB动态代理 | 继承机制,代理类继承了目标类并重写了目标方法,通过回调函数MethodInterceptor调用父类方法执行原始逻辑 | 通过FastClass方法索引调用 | 非接口类,非final类,非final方法 | 第一次调用因为要生成多个Class对象较JDK方式慢,多次调用因为有方法索引较反射方式快,如果方法过多switch case过多其效率还需测试 |
https://www.jianshu.com/p/9a61af393e41?from=timeline&isappinstalled=0
https://www.jianshu.com/p/13aa63e1ac95
https://www.cnblogs.com/cruze/p/3865180.html
spring技术内幕
相关文章推荐
- JDK动态代理与CGLIB动态代理应用及源码解析
- JDK动态代理与CGLIB动态代理应用及源码解析
- JDK动态代理与CGLIB动态代理应用及源码解析
- JDK动态代理与CGLIB动态代理应用及源码解析
- JDK动态代理与CGLIB动态代理应用及源码解析
- java动态代理——JDK和CGLIB原理解析与使用
- 动态代理源码解析之JDK
- 浅析Spring AOP源码(十三) jdk的动态代理和cglib的代理
- jdk的动态代理源码解析
- [教程]Java代理(静态,动态jdk和Cglib)简单应用
- 做一个合格的程序猿之浅析Spring AOP源码(十三) jdk的动态代理和cglib的代理
- JDK动态代理和CGLIB动态代理+源码下载
- 基于cglib实现的动态代理原理与源码解析
- 基于jdk动态代理的实现与源码解析
- Java--JDK动态代理核心源码解析
- tomcat源码分析3—>cglib动态代理深度解析
- Cglib动态代理源码例子解析
- jdk动态代理源码解析
- JDK动态代理和CGLIB动态代理+源码下载
- 《精通Spring4.X企业应用开发实战》读后感第七章(AOP基础知识、jdk动态代理,CGLib动态代理)