java.lang.reflect.Proxy

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

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);
}

Java 中,`java.lang.reflect.Proxy` 是一个非常重要的类,用于实现动态代理机制。它允许通过反射创建接口的代理实例,并将方法调用转发到指定的 `InvocationHandler`。以下是该类的部分核心源代码(以 OpenJDK 8 为例): ```java package java.lang.reflect; import java.security.ProtectionDomain; public class Proxy implements java.io.Serializable { private static final long serialVersionUID = -2222568059341876393L; protected InvocationHandler h; protected Proxy(InvocationHandler h) { this.h = h; } public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException { // 返回为指定接口生成的代理类 return ProxyFactory.getProxyClass(loader, interfaces); } public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } final Class<?> caller = System.getSecurityManager() == null ? null : Reflection.getCallerClass(); return ProxyFactory.getProxyInstance(loader, interfaces, h, caller); } public static boolean isProxyClass(Class<?> cl) { return Proxy.class.isAssignableFrom(cl) && ProxyFactory.isProxyClass(cl); } public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException { if (!isProxyClass(proxy.getClass())) { throw new IllegalArgumentException("Not a proxy instance"); } return ((Proxy) proxy).h; } } ``` 此外,`Proxy` 类依赖于内部的 `ProxyFactory` 来生成代理类。这部分逻辑涉及 JVM 的底层机制,并不完全在 Java 层面可见。生成的代理类会继承自 `Proxy` 并实现传入的接口,在调用接口方法时会委托给 `InvocationHandler` 处理。 ### 使用示例 以下是一个使用 `Proxy` 创建动态代理的简单示例: ```java import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface HelloService { String sayHello(String name); } class HelloServiceImpl implements HelloService { public String sayHello(String name) { return "Hello, " + name; } } class LoggingInvocationHandler implements InvocationHandler { private Object target; public LoggingInvocationHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before method call: " + method.getName()); Object result = method.invoke(target, args); System.out.println("After method call: " + method.getName()); return result; } } public class ProxyExample { public static void main(String[] args) { HelloService realService = new HelloServiceImpl(); HelloService proxyService = (HelloService) Proxy.newProxyInstance( realService.getClass().getClassLoader(), realService.getClass().getInterfaces(), new LoggingInvocationHandler(realService) ); String response = proxyService.sayHello("World"); System.out.println(response); } } ``` 在这个例子中,`Proxy.newProxyInstance` 方法创建了一个实现了 `HelloService` 接口的代理对象。所有对 `proxyService` 的方法调用都会被转发到 `LoggingInvocationHandler` 的 `invoke` 方法中,从而实现日志记录功能[^1]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值