`
Mysun
  • 浏览: 270745 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

JDK 1.5 Proxy 动态代理机制分析

阅读更多
Java的动态代理机制早在其1.3版本就已经引入了。在jdk1.5中,动态代理机制主要由两个类来实现,他们是Proxy类和InvocationHandler接口,他们都可以在java.lang.reflect包下面找到。
InvocationHandler接口里面只有一个方法invoke,为了使用的java的动态代理,用户需要实现这个接口,并且在invoke方法中写好调用实际方法的代码,同时还能在调用实际方法的前后加上其他的逻辑,比如日志或者事物操作等等。这个接口的实现类最终会被由jdk生成的动态代理类使用来调用实际的方法。关于如何使用java动态代理,请参阅网上其它文章,下面将要就Proxy生成动态代理类的源码进行分析。
在Proxy类里面,有两个方法跟动态代理类的生成有关,他们是:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException;

public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)
throws IllegalArgumentException

第一个方法比较简单,代码如下:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
throws IllegalArgumentException{
   if (h == null) {
      throw new NullPointerException();
   }
   /*
    * Look up or generate the designated proxy class.
    */
   Class cl = getProxyClass(loader, interfaces);
   /*
    * Invoke its constructor with the designated invocation handler.
    */
   try {
      Constructor cons = cl.getConstructor(constructorParams);
      return (Object) cons.newInstance(new Object[] { h });
   } catch (NoSuchMethodException e) {
      throw new InternalError(e.toString());
   } catch (IllegalAccessException e) {
      throw new InternalError(e.toString());
   } catch (InstantiationException e) {
      throw new InternalError(e.toString());
   } catch (InvocationTargetException e) {
      throw new InternalError(e.toString());
   }
}

可以看到,在newProxyInstance方法内部调用了getProxyClass方法,然后使用反射机制来创建由getProxyClass返回的动态代理类的实例。所以让我们重点来看一下getProxyClass这个方法。首先要说明一下在getProxyClass里面用到的几个类私有变量的作用。
/** maps a class loader to the proxy class cache for that loader */
private static Map loaderToCache = new WeakHashMap();
这个变量用来保存某个类加载器以及使用该加载器加载的动态代理类集合。key为类加载器,
value则是一个HashMap,里面放了具体的动态代理类,和用来索引的key。使用WeakHashMap是处于性能的考虑
/** marks that a particular proxy class is currently being generated */
private static Object pendingGenerationMarker = new Object();
用来标识一个动态代理类正在被创建,主要用来处理多线程的情况
/** next number to use for generation of unique proxy class names */
private static long nextUniqueNumber = 0;//用来生成唯一的动态代理类名时候用到
private static Object nextUniqueNumberLock = new Object();//锁对象
/** set of all generated proxy classes, for isProxyClass implementation */
private static Map proxyClasses = Collections.synchronizedMap(new WeakHashMap());
这个变量用来保存所有生成的所有动态代理类,主要是为了方便另外一个方法isProxyClass的使用设置的,在getProxyClass这个方法里面是没有什么用处的。同样适用的WeakHashMap,也是出于性能的考虑,不至于因为proxyClasses持有动态代理类的应用而导致垃圾回收器没法回收不再使用的动态代理类。

好了,介绍了变量,我们可以来关注一下getProxyClass方法了,这个方法大致可以分为三步,第一步是把传入的interface类的名字保存下来,第二步检查要用户请求的动态代理类是否已经存在了,如果已经存在那么就直接返回之前创建好的动态代理类。第三步就是当用户请求的动态代理类不存在的时候去创建这个动态代理类。让我们分别看一下这几部分的代码。
[list]
  • 第一步:
  •        /* collect interface names to use as key for proxy class cache */
    	String[] interfaceNames = new String[interfaces.length];
    
    	for (int i = 0; i < interfaces.length; i++) {
    	    /*
    	     * Verify that the class loader resolves the name of this
    	     * interface to the same Class object.
    	     */
    	    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");
    	    }
    
    	    /*
    	     * Verify that the Class object actually represents an
    	     * interface.
    	     */
    	    if (!interfaceClass.isInterface()) {
    		throw new IllegalArgumentException(
    		    interfaceClass.getName() + " is not an interface");
    	    }
    
    	    interfaceNames[i] = interfaceName;
    	}
    

    这一步比较好理解,就是获得各个interface类的名字,然后保存到一个字符串数组中。其中做了好几步的检查。需要说明的是,这个生成数组将会被用来作为索引动态代理类的key。
  • 第二步:
  •         //将之前生成的接口名字数组转成List,用来作为基于这组接口生成的动态代理
            //类的索引
            Object key = Arrays.asList(interfaceNames);
            /*
    	 * 检查对于作为参数输入的类加载器是否已经创建过了动态代理类缓存,如果没有
             * 就创建一个,如果有就取出来。
    	 */
    	Map cache;
    	synchronized (loaderToCache) {
    	    cache = (Map) loaderToCache.get(loader);
    	    if (cache == null) {
    		cache = new HashMap();
    		loaderToCache.put(loader, cache);
    	    }
               //下面这段话说明了使用WeakHashMap的好处
    	    /*
    	     * This mapping will remain valid for the duration of this
    	     * method, without further synchronization, because the mapping
    	     * will only be removed if the class loader becomes unreachable.
    	     */
    	}
            //下面这段代码用来检查实现了指定接口的动态代理是否已经被创建过了。
            synchronized (cache) {
                do{
                    //尝试用key从动态代理cache中取动态代理
    		Object value = cache.get(key);
    		if (value instanceof Reference) {
    		   proxyClass = (Class) ((Reference) value).get();
    		}
                    //如果动态代理已经存在,那么就直接返回找到的动态代理
    		if (proxyClass != null) {
    		// proxy class already generated: return it
    		   return proxyClass;
    		}
                    //如果没有找到动态代理,但是发现key对应的是一个
                    //pendingGenerationMarker对象,那就说面之前已经有别的线程已经在
                    //创建这个动态代理了,所以进入等待状态。负责创建的动态代理的
                    //那个线程创建完动态代理之后就会notify所有在cache上wait的线程
                    //这些线程被激活后就会继续执行do循环,然后发现动态代理已经被创建
                    //了,所以就直接返回被创建了动态代理
                    else if (value == pendingGenerationMarker) {
    		// proxy class being generated: wait for it
    		   try {
    			cache.wait();
    		   } catch (InterruptedException e) {
    		  /*
    	           * The class generation that we are waiting for should
    		   * take a small, bounded time, so we can safely ignore
    		   * thread interrupts here.
    		   */
    		   }
    			continue;
    		   }
                       //如果发现自己是第一个要创建动态代理的线程,就在对应的key上
                       //放置pendingGenerationMarker标志对象
                       else {
    		   /*
    		    * No proxy class for this list of interfaces has been
    		    * generated or is being generated, so we will go and
    		    * generate it now.  Mark it as pending generation.
                        */
    			cache.put(key, pendingGenerationMarker);
    			 break;
    		     }
    	    } while (true);
    	}
    
  • 第三步:创建动态代理
  •         try {
                //在动态代理的接口不是public的情况下,保存动态代理所在的包
    	    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.
    	     */
                //在动态代理的接口不是public的情况下,找出动态代理应该被创建在哪个包中
                //如果出现两个不同的包的非public Inteface就抛错
    	    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");
    		     }
    		 }
    	    }
    	    if (proxyPkg == null) {	// if no non-public proxy interfaces,
    		proxyPkg = "";		// use the unnamed package
    	    }
    
    	    {
    		/*
    		 * Choose a name for the proxy class to generate.
    		 */
                    //去一个数字,用来作为生成的动态代理的一部分
    		long num;
    		synchronized (nextUniqueNumberLock) {
    		    num = nextUniqueNumber++;
    		}
                    //动态代理类的名字,proxyClassNamePrefix是固定的,值为"$Proxy"
                    //java中合法的类名和变量名可以以$符开头
    		String proxyName = proxyPkg + proxyClassNamePrefix + num;
    		/*
    		 * Verify that the class loader hasn't already
    		 * defined a class with the chosen name.
    		 */
    
    		/*
    		 * Generate the specified proxy class.
    		 */
                    //下面就是创建动态代理的类文件,然后把生成的动态代理类加载进
                    //JVM中,下面用到的几个方法是java语言比较低层的机制,这里就
                    //不说了,有兴趣的可以看看源代码
    		byte[] proxyClassFile =	ProxyGenerator.generateProxyClass(
    		    proxyName, interfaces);
    		try {
    		    proxyClass = 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());
    		}
    	    }
    	    // add to set of all generated proxy classes, for isProxyClass
    	    proxyClasses.put(proxyClass, null);
    
    	} finally {
    	    /*
    	     * We must clean up the "pending generation" state of the proxy
    	     * class cache entry somehow.  If a proxy class was successfully
    	     * generated, store it in the cache (with a weak reference);
    	     * otherwise, remove the reserved entry.  In all cases, notify
    	     * all waiters on reserved entries in this cache.
    	     */
                //这里是用来擦屁股的,首先把生成的动态代理类加到对应的cache里面,然后
                //去激活所有被同一个cache阻塞的线程,通知他们动态代理已经生成的,好让 
                //他们继续执行。
                //如果动态代理因为各种情况没有生成成功,那么就把cache里面的key删除掉
    	    synchronized (cache) {
    		if (proxyClass != null) {
    		    cache.put(key, new WeakReference(proxyClass));
    		} else {
    		    cache.remove(key);
    		}
    		cache.notifyAll();
    	    }
    	}
            return proxyClass;
    

    [/list]

    分享到:
    评论
    1 楼 endall 2011-03-31  
    不错,结合Proxy原码,再看这篇文章,易懂

    相关推荐

    Global site tag (gtag.js) - Google Analytics