深入理解 jdk 动态代理的实现

来源:互联网 发布:佛山正大数据恢复中心 编辑:程序博客网 时间:2024/05/16 13:01

最近发现,java框架中大量使用了 动态代理。 原来只是会简单的使用,但是今天想深入研究下jdk是如何实现的。

一个比较靠谱的博客:http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html


至于Proxy 怎么用,在这里就不赘述了。关键是想说说 jdk怎么实现的。

主要想讲讲 这个方法

 Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces)

分几个步骤:

一、初始化接口参数

String[] interfaceNames = new String[interfaces.length];     //用来检查接口是否重复Set interfaceSet = new HashSet();//做一些验证,同时将 interfaceNames  装满for (int i = 0; i < interfaces.length; i++) {            String interfaceName = interfaces[i].getName();    Class interfaceClass = null;    try {interfaceClass = Class.forName(interfaceName, false, loader);    } catch (ClassNotFoundException e) {    }    if (interfaceClass != interfaces[i]) {throw new IllegalArgumentException(    interfaces[i] + " is not visible from class loader");    }    //判断是接口    interfaceClass.isInterface()) {throw new IllegalArgumentException(    interfaceClass.getName() + " is not an interface");    }    //判断接口是否重复    if (interfaceSet.contains(interfaceClass)) {throw new IllegalArgumentException(    "repeated interface: " + interfaceClass.getName());    }    interfaceSet.add(interfaceClass);   //将接口名称装入数组    interfaceNames[i] = interfaceName;}

二、通过类装载器,来找到当前是否有代理类Map的缓存。避免再次创建。 weakHashMap 是jdk 里的弱键map.直接和垃圾回器挂钩

Object key = Arrays.asList(interfaceNames);//通过class loader 来查找或者创建代理类 //loaderToCache 是一个 WeakHashMap() ,专门用来维护 类加载器和对应的代理类缓存Map cache;synchronized (loaderToCache) {    cache = (Map) loaderToCache.get(loader);    if (cache == null) {cache = new HashMap();loaderToCache.put(loader, cache);    }}

三、针对具体的接口名称集合,来找缓存

//主要是从缓存中查找是否代理对象。//如果没有代理类对象,判断是否有别的线程正在生成当前代理独享synchronized (cache) {    do {    //以接口名称数组为key,从缓存中代理类Object value = cache.get(key);//判断是接口if (value instanceof Reference) {    proxyClass = (Class) ((Reference) value).get();}//找到了直接返回if (proxyClass != null) {    return proxyClass;} //没找到,pendingGenerationMarker 是一个标记对象,用来表示当前代理对象是否正在产生else if (value == pendingGenerationMarker) {    // 代理对象正在生成,线程阻塞。    try {cache.wait();    } catch (InterruptedException e) {    }    continue;} else {//当前没有代理对象正在创建,标记该接口列表的代理对象正在创建    cache.put(key, pendingGenerationMarker);    break;}    } while (true);}

四、代理对象名的产生

//针对一些非public 的接口,得到代理类生成的包路径try {    String proxyPkg = null;// package to define proxy class in    for (int i = 0; i < interfaces.length; i++) {int flags = interfaces[i].getModifiers();if (!Modifier.isPublic(flags)) {    String name = interfaces[i].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");    }}    }    //如果全部是public 接口    if (proxyPkg == null) {proxyPkg = "";    }    {long num;//当前对象代理对象统一数量管理synchronized (nextUniqueNumberLock) {    num = nextUniqueNumber++;}//代理对象新的名称String proxyName = proxyPkg + proxyClassNamePrefix + num;

四、最关键的一步,生成代理对象

//通过 ProxyGenerator 得带代理类的class 的二进制数据byte[] proxyClassFile =ProxyGenerator.generateProxyClass(    proxyName, interfaces);try {//调用本地方法,然后直接返回    proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);} catch (ClassFormatError e) {    throw new IllegalArgumentException(e.toString());}    }    proxyClasses.put(proxyClass, null);} finally {//别忘了,最终要释放还要告知别的线程,代理对象创建完毕。    synchronized (cache) {if (proxyClass != null) {    cache.put(key, new WeakReference(proxyClass));} else {    cache.remove(key);}//通知阻塞线程cache.notifyAll();    }}return proxyClass;

ok,这个最主要的方法讲完了。

想说明下,其实jdk自带的动态代理生成的代理类,无非就是如下格式

public final class ProxySubject(被代理的类) extends Proxy implements interface(接口集合){//自己定义的InvocationHandlerInvocationHandler invocationHandler;//构造方法,public ProxySubject(InvocationHandler invocationHandler){this.invocationHandler = invocationHandler;}//接口的方法public void method{invocationHandler.invoke(this, method(被调用方法对象), null)}}

关键还是通过继承来实现,也就意味着,被代理对象的父对象无法被动态代理。


0 0
原创粉丝点击