• 上午捉摸了一下java的动态proxy

    2004-04-14

    Tag:

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://piginzoo.blogbus.com/logs/139822.html

     上午捉摸了一下java的动态proxy

     开始时候,这样写:
     interface IOneClass{
     .....
     class OneClass implements IOneClass
     .....
      InvocationHandler handler = new MyInvocationHandler();
      IOneClass one =
       (IOneClass) Proxy.newProxyInstance(
        OneClass.class.getClassLoader(),
        new Class[] { IOneClass.class },
        handler);
      one.hello_public("xxx");

     一直纳闷,OneClass啥时候传入呢?
     后来修改了,

      InvocationHandler handler = new MyInvocationHandler(new OneClass());
     ...... 

     class MyInvocationHandler implements InvocationHandler {
     private IOneClass one;
     public MyInvocationHandler(IOneClass theone){
      one = theone;<--------这里传入了
     }
     
     public Object invoke(Object proxy, Method method, Object[] args)  throws Throwable {
      System.out.println("proxyed class name:" + proxy.getClass().getName());
      System.out.println("calling method:" + method.getName());
      System.out.println("param:" + args[0]);
      return method.invoke(one, args);
        //<------这里使用的就是OneClass的实例 
     }
     
     不过,感觉这样好像很牵强附会似的,不过这是我能把OneClass的实例唯一绑定上的地方
     看来,还得化点时间学习一下


     //-----------------------------------------------------
     今天中午吃饭的时候,还跟七彩浪聊呢,动态代理是如何实现的呢?
     我的观点是:一定是java虚拟机里面放了个映射表,你运行Proxy.newInstance时候就好像
     注册一样,吧某个类如何被代理的信息放到映射表中,下次一调用某个类,虚拟机就到注册
     表中一找,发现有代理,就先运行代理了,呵呵。
     
     狼的观点是,一定是某个类被修改了字节码,他的行为就变了,后来我一想,这不就是aspectj
     的静态编入呢。

     终于,下午花了点时间看了看 java.lang.reflect.Proxy的源代码,发现了一些有意思的东西;

     getProxyClass()方法是proxy类的核心:
     /*
      * Find or create the proxy class cache for the class loader.
      */
     Map cache;
     synchronized (loaderToCache) {
         cache = (Map) loaderToCache.get(loader);
         if (cache == null) {
      cache = new HashMap(3);
      loaderToCache.put(loader, cache);
         }
         /*
          * 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.
          */
     }

     /*
      * Look up the list of interfaces in the proxy class cache using
      * the string key.  This lookup will result in one of three possible
      * kinds of values:
      *     null, if there is currently no proxy class for the list of
      *         interfaces in the class loader,
      *     the pendingGenerationMarker object, if a proxy class for the
      *         list of interfaces is currently being generated,
      *     or a weak reference to a Class object, if a proxy class for
      *         the list of interfaces has already been generated.
      */
     synchronized (cache) {
         /*
          * Note that we need not worry about reaping the cache for
          * entries with cleared weak references because if a proxy class
          * has been garbage collected, its class loader will have been
          * garbage collected as well, so the entire cache will be reaped
          * from the loaderToCache map.
          */
         do {
      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;

     你看,果然是有各cache,存放这些代理类。
     那么,如果没有,代理类如何产生呢,别着急,答案就在下面
      /*
       * Verify that the class loader hasn't already
       * defined a class with the chosen name.
       */

      /*
       * Generate the specified proxy class.
       */
      byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
          proxyName, interfaces);
      try {
          proxyClass = defineClass0(loader, proxyName,
       proxyClassFile, 0, proxyClassFile.length);

      看到了吧,ProxyGenerator.generateProxyClass()
      动态产生一个类定义,然后还原成一个类(Class)。

     
     另外,InvokeHandler是通过构造函数传入动态代理类的,这点从
     Porxy.newProxyInstance()的方法就可以看出:
        public static Object newProxyInstance(ClassLoader loader,
           Class[] interfaces,
           InvocationHandler h)
     throws IllegalArgumentException
        {
     if (h == null) {
         throw new NullPointerException();
     }

     Class cl = getProxyClass(loader, interfaces);

     try {
         Constructor cons = cl.getConstructor(constructorParams);
         return (Object) cons.newInstance(new Object[] { h });
           <-------h就是InvocationHandler的实例

     总之,对于动态代理,确实给我们提供了一个很好的机制,
     来改变一个类的一些行为,不过,有一点不爽,就是,
     被代理的类必须先得有一个interface才行。

     回头看看nanning和cglib如何解决的这个问题吧。


    随机文章:

    最近的体会 2004-10-15
    关键是心情 2004-07-25
    工作第二天 2004-03-02

    收藏到:Del.icio.us