java.lang.reflect.Proxy

本文深入探讨Java动态代理机制,介绍如何使用Java反射API创建动态代理类及其实例。通过具体示例展示动态代理的工作原理及其应用场景,如AOP技术中的运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package java.lang.reflect;

import java.lang.ref.*;
import java.util.*;

import sun.misc.ProxyGenerator;

/**
 * 使用proxy的例子
 *
interface tt {
 String getSt();
}

class stt implements tt {
 public String getSt() {
  return "lqtest";
 }
}

class MyHandler implements InvocationHandler {
 tt obj;
 
 public MyHandler(tt obj) {
  this.obj = obj;
 }
 
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  System.out.println("this is my test");
  return method.invoke(obj, args);
 }
}

  stt t = new stt();
  MyHandler hd = new MyHandler(t);
  
  tt k = (tt) Proxy.newProxyInstance(tt.class.getClassLoader(), new Class[] {tt.class}, hd);  
  String rtSt = k.getSt();
  
  Class proxyClazz = Proxy.getProxyClass(tt.class.getClassLoader(), new Class[] {tt.class});
  tt k2 = (tt) proxyClazz.getConstructor(new Class[] {InvocationHandler.class}).newInstance(new Object[] {hd});
  String rrSt2 = k2.getSt();
 * 这两种方式都会在控制台打印出字符串 
 * 代理会动态生成类proxyClazz,虽然我们装载类常常装载的是一个*.Class文件但实际上
 * 符合Class文件格式的byte数组也可以被ClassLoader装载,如果我们熟悉Class文件的格式,
 * 我们可以使用编程的方式动态生成类,而不局限只生成简单的代理类,这种能力sun并没有实现
 *
 * 代理类这种技巧常被使用在Aop技术中 
 *
 * comment by liqiang
 *
 * @author Peter Jones
 *
 */
public class Proxy implements java.io.Serializable {

    //proxy类的前缀
    private final static String proxyClassNamePrefix = "$Proxy";

    //构造函数的参数类型
    private final static Class[] constructorParams =
 { InvocationHandler.class };

    //ClassLoader与proxy类缓存对应的缓存
    private static Map loaderToCache = new WeakHashMap(3);

    //对应的Proxy类正在被创建的标志
    private static Object pendingGenerationMarker = new Object();

    //用来创建唯一的Proxy类名
    private static long nextUniqueNumber = 0;
    //为创建唯一类名使用的锁
    private static Object nextUniqueNumberLock = new Object();

    //存放所有创建的proxy类对象
    private static Map proxyClasses =
 Collections.synchronizedMap(new WeakHashMap(3));

    /**
     * the invocation handler for this proxy instance.
     * @serial
     */
    protected InvocationHandler h;

    /**
     * Prohibits instantiation.
     */
    private Proxy() {
    }

    //以InvocationHandler对象做为参数的构造函数
    protected Proxy(InvocationHandler h) {
 this.h = h;
    }

    /**
     *
     * 动态生成proxy类
     * 它有以下限制
     * 1接口数组中的每个元素应代表接口,不能表示类,或原始类型
     * 2不能出现重复的类型
     * 3Class.forName(i.getName(), false, cl) == i 成立表示接口可以
     * 通过名称访问到
     * 4两个接口不能存在方法名与参数列表相同但返回值不同的情况
     * 5接口的最大数为65535
     * 如果有以上情况则抛出IllegalArgumentException
     * 如果数组中有null的元素则抛出NullPointerException
     * 接口的顺序不同会生成不同的proxy Class
     *
     *
     * @param loader 装载这个proxy类的ClassLoader
     * @param interfaces 接口列表
     *
     */
    public static Class getProxyClass(ClassLoader loader,
          Class[] interfaces)
 throws IllegalArgumentException
    {
    //存放动态生成的类对象
 Class proxyClass = null;

 //生成proxy缓存的键值的StringBuffer
 StringBuffer keyBuffer = new StringBuffer();

 for (int i = 0; i < interfaces.length; i++) {
     Class interfaceClass = null;
    
     try {
     //判断是否通过名称可以取得接口类对象
  interfaceClass =
      Class.forName(interfaces[i].getName(), false, loader);
     } catch (ClassNotFoundException e) {
     }
    
     //如果不能通过名称取得接口类对象则抛出异常,这时interfaceClass为null
     if (interfaceClass != interfaces[i]) {
  throw new IllegalArgumentException(
      interfaces[i] + " is not visible from class loader");
     }

     //如果接口数组中的元素不是接口则抛出异常
     if (!interfaceClass.isInterface()) {
  throw new IllegalArgumentException(
      interfaceClass.getName() + " is not an interface");
     }

     //用";"连接接口名,生成缓存的键
     keyBuffer.append(interfaces[i].getName()).append(';');
 }

 //生成String的缓存键值,这样别使用集合效率高
 String key = keyBuffer.toString();

 /*
  * Find or create the proxy class cache for the class loader.
  */
 Map cache;
 synchronized (loaderToCache) {
  //取得相应ClassLoader对象对象的proxy类缓存
     cache = (Map) loaderToCache.get(loader);
    
     if (cache == null) {
     //如果没有与此ClassLoader对应的缓存则创建它
  cache = new HashMap(3);
  loaderToCache.put(loader, cache);
     }
    
     //在此方法的后续部分loaderToCache依然有效,但不对它做同步是因为
     //只在loader不可触及时mapping才被移除
 }

 //通过String的键值查找Proxy类,会有三种情况:
 //1如果当前缓存总没有此Proxy类则返回null
 //2如果Proxy类正在创建则返回pendingGenerationMarker对象
 //3如果此Proxy类已经被创建,则返回WeakReference对象
 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 {
     //通过接口列表键值取出封装Proxy类对象的Reference对象
  Object value = cache.get(key);
  if (value instanceof Reference) {
   //从reference对象中取出proxy类对象
      proxyClass = (Class) ((Reference) value).get();
  }
  
  if (proxyClass != null) {
      //如果Proxy类对象已经创建则直接返回
      return proxyClass;
  } else if (value == pendingGenerationMarker) {
      //如果Proxy对象正在被创建则等待
      try {
   cache.wait();
      } catch (InterruptedException e) {
      //创建Class的过程很短,且为定长时间,所以这里忽略了中断处理
      }
     
      //Proxy被创建,或被中断,则继续通过键值取缓存中的Proxy类对象
      continue;
  } else {
      //如果没有创建则标志它正在创建
      cache.put(key, pendingGenerationMarker);
      //跳出循环,创建此Proxy类
      break;
  }
     } while (true);
 }

 try {
  //Proxy类的包
     String proxyPkg = null;

     /*
      * 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 (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)) {
      //接口不为public且有不在同一个包下则抛出异常
   throw new IllegalArgumentException(
       "non-public interfaces from different packages");
      }
  }
  
     }

     if (proxyPkg == null) {//如果没有非public的接口
  proxyPkg = "";  //使用匿名包
     }

     //使用了一个块
     {
  /*
   * Choose a name for the proxy class to generate.
   */
  long num;
  synchronized (nextUniqueNumberLock) {
   //这里使用静态属性作为锁,保护了同步区域内的数据
   //因为num是long型的,无法对原始对象加锁(只能对类加锁)
   //而如果对整个当前对象加锁会浪费性能
   //使用一个锁对象,还可达到同时保护多个数据(对象,原始类型)的效果

      num = nextUniqueNumber++;
  }
  
  //拼出新的类名,类名的拼法是包名+$Proxy+唯一的long型值
  String proxyName = proxyPkg + proxyClassNamePrefix + num;
  
  //生成Class类的字节码
  byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
      proxyName, interfaces);
  
  try {
   //装载此类
      proxyClass = defineClass0(loader, proxyName,
   proxyClassFile, 0, proxyClassFile.length);
  } catch (ClassFormatError e) {
      throw new IllegalArgumentException(e.toString());
  }
     }
    
     //将新创建的类对象放到存放已创建过的Proxy类的类对象的set
     proxyClasses.put(proxyClass, null);

 } finally {
     synchronized (cache) {
  if (proxyClass != null) {
   //如果创建成功则重置缓存中的值,原来是pendingGenerationMarker
      cache.put(key, new WeakReference(proxyClass));
  } else {
   //创建不成功,则删除掉此键对应项
      cache.remove(key);
  }
  
  //唤醒全部因为碰到Proxy类正在创建状态而挂起的进程
  cache.notifyAll();
     }
 }
 
 return proxyClass;
    }

    /**
     * 创建一个Proxy Object的快速方法
     *
     * @param loader 装载此Proxy类的ClassLoader
     * @param interfaces 接口列表
     * @param   h InvocationHandler对象
     *
     */
    public static Object newProxyInstance(ClassLoader loader,
       Class[] interfaces,
       InvocationHandler h)
 throws IllegalArgumentException
    {
 if (h == null) {
  //如果InvocationHandler为null则抛出异常
     throw new NullPointerException();
 }

 //得到Proxy类
 Class cl = getProxyClass(loader, interfaces);

 try {
  //获得有一个InvocationHandler对象参数的构造函数
     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());
 }
    }

    //判断指定Class类是否被创建
    public static boolean isProxyClass(Class cl) {
 if (cl == null) {
     throw new NullPointerException();
 }

 return proxyClasses.containsKey(cl);
    }

    //如果proxy是Proxy对象则获得其getInvocationHandler对象,否则抛出异常
    public static InvocationHandler getInvocationHandler(Object proxy)
 throws IllegalArgumentException
    {
 //检测proxy对象是否是已经生成的Proxy类的对象
 if (!isProxyClass(proxy.getClass())) {
     throw new IllegalArgumentException("not a proxy instance");
 }

 //如果是则转型
 Proxy p = (Proxy) proxy;
 return p.h;
    }

    //加载类的本地方法
    private static native Class defineClass0(ClassLoader loader, String name,
          byte[] b, int off, int len);
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值