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