代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

动态代理是一种比较常用的代理方式,也许你已经很熟悉它的使用了,但是它的实现原理你是否搞懂?不得不说搞懂动态代理的机制是很有必要的。为什么?当前十分火爆的Retrofit你应该很熟悉,没错,Retrofit就使用了动态代理。这么牛逼的框架都在使用的技术,你还不来学学它的原理么。

注意:JDK动态代理要求被代理类必须实现接口,而且对于private方法JDK动态代理也是无能无力的。当然,你会说那还玩毛线,直接用CGLIB不就行了,没错,CGLIB直接支持类,但是很遗憾,CGLIB不能再Android中使用,Android虚拟机还是与JVM有不同之处 的。

动态代理的特点是编译阶段没有代理类在运行时才生成代理类。

以下分析基于JDK1.7

示例下载(包含生成的代理类字节码文件,可以反编译查看):http://download.csdn.net/download/json_it/10148805

1、使用示例

定义接口:
public interface ITestDynamicProxy {void doSomething();
}

实现类:

public class TestDynamicProxy implements ITestDynamicProxy {@Overridepublic void doSomething() {System.out.println("doSomething()");}
}

自定义InvocationHandler:

public class MyInvoxationHandler implements InvocationHandler {private Object proxied;public MyInvoxationHandler(Object proxied) {this.proxied = proxied;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("你可以在这里做一些其他的工作=====");return method.invoke(proxied, args);}
}

动态代理使用:

public class MyDynamicProxy {public static void main(String[] args) {TestDynamicProxy testDynamicProxy = new TestDynamicProxy();ITestDynamicProxy proxy = (ITestDynamicProxy) Proxy.newProxyInstance(ITestDynamicProxy.class.getClassLoader(),new Class[] { ITestDynamicProxy.class },new MyInvoxationHandler(testDynamicProxy));proxy.doSomething();}
}

----> 你可以在这里做一些其他的工作=====

doSomething()

可以看到,代码量并不是很大。而且看起来也不是很复杂。说实话,以前初次接触动态代理的时候,我还是很疑惑的。这简短的几行代码背后到底发生了什么?动态代理给开发者带来了哪些惊喜呢?

2、原理分析

Proxy.newProxyInstance(...)是动态代理的入口,它为我们生成了代理类:

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

该方法有三个参数:

ClassLoader:被代理类的类加载器;

Class<?> interfaces:被代理类实现的接口数组;
InvocationHandler:与被代理类关联的handler;

 @CallerSensitivepublic static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{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<?> cl = getProxyClass0(loader, intfs);//关键方法,获取代理类/** Invoke its constructor with the designated invocation handler.*/try {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 permissionreturn 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());}}private static Object newInstance(Constructor<?> cons, InvocationHandler h) {try {return cons.newInstance(new Object[] {h} );//生成代理类的实例} catch (IllegalAccessException | InstantiationException e) {throw new InternalError(e.toString());} catch (InvocationTargetException e) {Throwable t = e.getCause();if (t instanceof RuntimeException) {throw (RuntimeException) t;} else {throw new InternalError(t.toString());}}}

可以看到,比较关键的方法是getProxyClass0(..)方法、

 private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {if (interfaces.length > 65535) {throw new IllegalArgumentException("interface limit exceeded");}// If the proxy class defined by the given loader implementing// the given interfaces exists, this will simply return the cached copy;// otherwise, it will create the proxy class via the ProxyClassFactoryreturn proxyClassCache.get(loader, interfaces);}

在这个方法中,我们发现其使用了缓存,通过loader和interfaces来获取代理类。有了缓存,我们很自然的就会想到,如果缓存中存在,则直接使用。否则,生成新的代理类。关于如何缓存,不再介绍。我们只需抓住关键思想,毕竟缓存不是我们分析的重点。

那么,这个proxyClassCache是一个什么东西呢?

private static final WeakCache<ClassLoader, Class<?>[], Class<?>>proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

它的两个参数让我们想到,第一个应该是用于产生Key的工厂,而第二个则是用于生成代理Class的工厂。

 public V get(K key, P parameter) {Objects.requireNonNull(parameter);expungeStaleEntries();Object cacheKey = CacheKey.valueOf(key, refQueue);// lazily install the 2nd level valuesMap for the particular cacheKeyConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);if (valuesMap == null) {ConcurrentMap<Object, Supplier<V>> oldValuesMap= map.putIfAbsent(cacheKey,valuesMap = new ConcurrentHashMap<>());if (oldValuesMap != null) {valuesMap = oldValuesMap;}}// create subKey and retrieve the possible Supplier<V> stored by that// subKey from valuesMapObject subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));Supplier<V> supplier = valuesMap.get(subKey);Factory factory = null;while (true) {if (supplier != null) {// supplier might be a Factory or a CacheValue<V> instanceV value = supplier.get();//关键方法if (value != null) {return value;}}// else no supplier in cache// or a supplier that returned null (could be a cleared CacheValue// or a Factory that wasn't successful in installing the CacheValue)// lazily construct a Factoryif (factory == null) {factory = new Factory(key, parameter, subKey, valuesMap);}if (supplier == null) {supplier = valuesMap.putIfAbsent(subKey, factory);if (supplier == null) {// successfully installed Factorysupplier = factory;}// else retry with winning supplier} else {if (valuesMap.replace(subKey, supplier, factory)) {// successfully replaced// cleared CacheEntry / unsuccessful Factory// with our Factorysupplier = factory;} else {// retry with current suppliersupplier = valuesMap.get(subKey);}}}}

这段代码的主要思想是这样的:

查看缓存中是否存在 --> 如果存在,则直接返回supplier,get()-->如果不存在,则先生成Supplier(Factory是Supplier的子类),然后通过get()方法返回代理类。

现在最关键的就是这个get方法:

@Overridepublic synchronized V get() { // serialize access// re-checkSupplier<V> supplier = valuesMap.get(subKey);if (supplier != this) {// something changed while we were waiting:// might be that we were replaced by a CacheValue// or were removed because of failure ->// return null to signal WeakCache.get() to retry// the loopreturn null;}// else still us (supplier == this)// create new valueV value = null;try {value = Objects.requireNonNull(valueFactory.apply(key, parameter));} finally {if (value == null) { // remove us on failurevaluesMap.remove(subKey, this);}}// the only path to reach here is with non-null valueassert value != null;// wrap value with CacheValue (WeakReference)CacheValue<V> cacheValue = new CacheValue<>(value);// try replacing us with CacheValue (this should always succeed)if (valuesMap.replace(subKey, this, cacheValue)) {// put also in reverseMapreverseMap.put(cacheValue, Boolean.TRUE);} else {throw new AssertionError("Should not reach here");}// successfully replaced us with new CacheValue -> return the value// wrapped by itreturn value;}}

我们终于发现了最关键的信息:

value = Objects.requireNonNull(valueFactory.apply(key, parameter));这个valueFactory是什么?就是ProxyClassFactory。

   @Overridepublic Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);for (Class<?> intf : interfaces) {/** Verify that the class loader resolves the name of this* interface to the same Class object.*/Class<?> interfaceClass = null;try {interfaceClass = Class.forName(intf.getName(), false, loader);} catch (ClassNotFoundException e) {}if (interfaceClass != intf) {throw new IllegalArgumentException(intf + " is not visible from class loader");}/** Verify that the Class object actually represents an* interface.*/if (!interfaceClass.isInterface()) {throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");}/** Verify that this interface is not a duplicate.*/if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());}}String proxyPkg = null;     // package to define proxy class in/** Record the package of a non-public proxy interface so that the* proxy class will be defined in the same package.  Verify that* all non-public proxy interfaces are in the same package.*/for (Class<?> intf : interfaces) {int flags = intf.getModifiers();if (!Modifier.isPublic(flags)) {String name = intf.getName();int n = name.lastIndexOf('.');String pkg = ((n == -1) ? "" : name.substring(0, n + 1));if (proxyPkg == null) {proxyPkg = pkg;} else if (!pkg.equals(proxyPkg)) {throw new IllegalArgumentException("non-public interfaces from different packages");}}}if (proxyPkg == null) {// if no non-public proxy interfaces, use com.sun.proxy packageproxyPkg = ReflectUtil.PROXY_PACKAGE + ".";}/** Choose a name for the proxy class to generate.*/long num = nextUniqueNumber.getAndIncrement();String proxyName = proxyPkg + proxyClassNamePrefix + num;/** Generate the specified proxy class.*/byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);try {return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);} catch (ClassFormatError e) {/** A ClassFormatError here means that (barring bugs in the* proxy class generation code) there was some other* invalid aspect of the arguments supplied to the proxy* class creation (such as virtual machine limitations* exceeded).*/throw new IllegalArgumentException(e.toString());}}}

关键信息:

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);

由此,我们找到了最终JDK是通过ProxyGenerator的generateProxyClass方法产生了最终的字节码。我们也可以利用这个类的方法将字节码保存到本地,然后反编译看一下代理类庐山真面目。

public class MyDynamicProxy {public static void main(String[] args) {TestDynamicProxy testDynamicProxy = new TestDynamicProxy();ITestDynamicProxy proxy = (ITestDynamicProxy) Proxy.newProxyInstance(ITestDynamicProxy.class.getClassLoader(),new Class[] { ITestDynamicProxy.class },new MyInvoxationHandler(testDynamicProxy));proxy.doSomething();createProxyClassFile();}private static void createProxyClassFile() {String name = "ProxySubject";byte[] data = ProxyGenerator.generateProxyClass(name,new Class[] { ITestDynamicProxy.class });FileOutputStream out = null;try {out = new FileOutputStream(name + ".class");System.out.println((new File("hello")).getAbsolutePath());out.write(data);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if (null != out)try {out.close();} catch (IOException e) {e.printStackTrace();}}}}

找到我们生成的ProxySubject.class,反编译看下:

import com.example.proxy.ITestDynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;public final class ProxySubjectextends Proxyimplements ITestDynamicProxy
{private static Method m1;private static Method m0;private static Method m3;private static Method m2;public ProxySubject(InvocationHandler paramInvocationHandler)throws {super(paramInvocationHandler);}public final boolean equals(Object paramObject)throws {try{return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();}catch (Error|RuntimeException localError){throw localError;}catch (Throwable localThrowable){throw new UndeclaredThrowableException(localThrowable);}}public final int hashCode()throws {try{return ((Integer)this.h.invoke(this, m0, null)).intValue();}catch (Error|RuntimeException localError){throw localError;}catch (Throwable localThrowable){throw new UndeclaredThrowableException(localThrowable);}}public final void doSomething()throws {try{this.h.invoke(this, m3, null);return;}catch (Error|RuntimeException localError){throw localError;}catch (Throwable localThrowable){throw new UndeclaredThrowableException(localThrowable);}}public final String toString()throws {try{return (String)this.h.invoke(this, m2, null);}catch (Error|RuntimeException localError){throw localError;}catch (Throwable localThrowable){throw new UndeclaredThrowableException(localThrowable);}}static{try{m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);m3 = Class.forName("com.example.proxy.ITestDynamicProxy").getMethod("doSomething", new Class[0]);m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);return;}catch (NoSuchMethodException localNoSuchMethodException){throw new NoSuchMethodError(localNoSuchMethodException.getMessage());}catch (ClassNotFoundException localClassNotFoundException){throw new NoClassDefFoundError(localClassNotFoundException.getMessage());}}
}

代理类是proxy的子类,实现了代理接口。除了生成常用的几个通用的方法外,还生成了代理接口方法:

public final void doSomething()throws {try{this.h.invoke(this, m3, null);return;}catch (Error|RuntimeException localError){throw localError;}catch (Throwable localThrowable){throw new UndeclaredThrowableException(localThrowable);}}

可以看到对代理类的代理接口的调用会被转发为由InvocationHandler这个接口的 invoke(对方法的增强就写在这里面) 方法来进行调用。这也是为什么需要我们来实现InvocationHandler,并在其invoke方法中完成主要工作的原因了。

动态代理[JDK]机制解析相关推荐

  1. 使用 cglib_java动态代理(JDK和CGLIB原理解析与使用)

    CGLIB的动态代理 原理 代理为控制要访问的目标对象提供了一种途径.当访问对象时,它引入了一个间接的层.JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理.JDK的动态代理用起 ...

  2. java动态代理(JDK和cglib)详解

    JAVA的动态代理  代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委 ...

  3. JAVA 进阶篇 动态代理 JDK动态代理和CGlib动态代理

    JDK动态代理和CGlib动态代理 JDK动态代理: 利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. CGlib动态代理: 利用ASM(开源的Java ...

  4. Java两种动态代理JDK动态代理和CGLIB动态代理

    目录 代理模式 JDK动态代理 cglib动态代理 测试 代理模式 代理模式是23种设计模式的一种,他是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式.为了对外开放协议,B往往实现了一个 ...

  5. 动态代理jdk和cglib区别、注意事项(private,static,final)、spring aop原理

    文章目录 一.代理简聊 二.静态代理 三.动态代理 1.jdk动态代理 2.cglib动态代理 四.动态代理总结.注意事项 1.jdk动态代理与cglib的区别. 2.注意事项及分析. 五.aop原理 ...

  6. 动态代理——CGLIB动态代理原理示例解析

    觉得可以的话点个关注,转个发呗,陆续奉上干货~~~~ 前文我们讲解了JDK动态代理的原理(动态代理--JDK动态代理原理),今天我们来看看CGLIB动态代理是如何实现,最后我们总结下JDK动态代理和C ...

  7. Spring AOP【AOP的基本实现与动态代理JDK Proxy 和 CGLIB区别】

    Spring AOP[AOP的基本实现与动态代理JDK Proxy 和 CGLIB区别]

  8. Filter过滤器和动态代理处理机制和案例(Filter过滤器和动态代理结合)

    关注公众号:"奇叔码技术" 回复:"java面试题大全"或者"java面试题" 即可免费领取资料 Filter过滤器和动态代理处理机制和案例 ...

  9. java动态代理原理及解析

    转载自 http://blog.csdn.net/scplove/article/details/52451899 代理:设计模式 代理模式是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制 ...

最新文章

  1. 《评人工智能如何走向新阶段》后记(深谈人工智能发展前沿)
  2. 线性回归模型中的多重共线性--Multicollinearity
  3. 类和对象:给大家介绍对象
  4. 【vue.js】vue后台项目权限功能实现思路
  5. python怎么网络通信_深入Python中的网络通信
  6. 两个三维图像互信息python_python – 使用numpy计算成对互信息的最佳方式
  7. C# Thread开启线程几种方式
  8. 克制懒惰之飞鸽传书版
  9. python动态心形代码_父亲节,程序员几条代码硬核示爱
  10. NHibernate入门实例
  11. SpringBoot与缓存使用及原理(上)
  12. Teststand 界面打不开问题解决
  13. 图论-度序列可图性判断(Havel-Hakimi定理)
  14. 基于springboot的实验室预约管理系统(完美运行,数据库源代码,可远程调试)
  15. 苏州源特国产隔离DC-DC电源芯片替代SN6505/SGM46000/MAX256/B0505-1W的方案
  16. Keil系列软件安装(二)Keil5 MDk
  17. 【Linux系统管理】03 Linux 安装 04 初学者建议
  18. NoteExpress文献导入,信息显示不全的问题
  19. Python有哪些技术上的优点?比其他语言好在哪儿?
  20. Unity HoloLens 开发调试及部署配置【新】

热门文章

  1. uniapp里css不是识别*,报 error at token “*“
  2. 短信服务-重要消息通知解决方案
  3. Alist保姆级搭建教程
  4. 插件化基础(二)——加载插件资源
  5. 支付宝微信刷脸支付开始在全国推广
  6. 自动驾驶年度激辩:量产由三要素驱动,本质是数据的军备竞赛 | MEET2022
  7. 《守望先锋》模型提取实例
  8. 由百家讲坛的《大隋风云-之流星王朝》想到的
  9. AI初创公司新机遇,谷歌苹果竞相收购
  10. python数学圆周率_Python编程超简单方法算圆周率