写到代理模式这章,不得不提到 JDK 中的动态代理,它是 java 语言自身对动态代理的支持,类似于 JDK 中在 java.util 包中提供 Observable 类和 Observer 接口提供对观察者模式的语言级支持。关于动态代理的好处可以从网络上流行的 <<JAVA 中用动态代理类实现记忆功能 >> 、 << 使用 JAVA 中的动态代理实现数据库连接池 >> 、 << 通过 JAVA 的动态代理机制控制事务 >> 、 << 用 Java 动态代理实现 AOP>>…… 看出动态代理的优点――动态地为软件增加功能。应用的文章很多,出于自身的好奇我们来研究 JDK 中动态代理的实现吧!这就是本博客所谓的“任何东西只有精通了,才能更好地使用”,有别于所谓的“很好地使用它,然后再去精通它”。下面我们开始对 java 语言中动态代理的源代码的研究吧!
一、动态代理的相关类
JDK 中和动态代理直接相关的主要有 InvocationHandler 接口和 Proxy 类。 InvocationHandler 接口相当于 Proxy 类的 CallBack Interface 。
下图为 InvocationHandler 接口的类图,该接口中仅定义了 Object : invoke(Object obj,Method method, Object [] args) 一个方法。第一个参数 proxy 一般是指具体的被代理类,即代理模式中的目标对象; method 是被代理的方法, args 为该方法的参数数组。该接口在动态代理中由客户实现。
三、 Proxy 类
Proxy 为动态代理类,是动态代理的核心类,其作用类似于代理模式中的代理。从上面的类图可以看出 Proxy 类中包含的全是静态的方法和成员变量,这是一个纯粹的工具类,因此其源代码中含有一个私有的构造器,在某种意义上可以看作为一个单例模式的特殊情形。(原因为: 1. 不能实例化; 2. 提供统一的入口)。这个类中包含很多很有意思的实现,下面我们还是看看其源代码吧!
package java.lang.reflect;
import java.lang.ref.*;
import java.util.*;
import sun.misc.ProxyGenerator; //sun 将产生代理对象的类,放在 sun.misc 包中
public class Proxy implements java.io.Serializable { // 实现了 Serializable 接口,因此可以保存到流中
private static final long serialVersionUID = -2222568056686623797L; // 序列化时使用的版本号
// 以下的变量用于代理对象创建时,名称各部分的组合
// 以下几个成员变量组合在一起,形成被创建的代理对象的名称
// 这些被 ProxyGenerator 创建的代理对象,以此名字,存入当前 Proxy 对象内部的 cache 中
// 被创建代理对象的名称包含 3 部分:
// 1. 包名 proxyPkg ; 2. 代理对象的名称前缀; 3. 代理被创建的数目 num;
// 该数目表示当前被创建的代理对象是使用 ProxyGenerator 创建的第 n 个代理对象
// 下面是代理对象的名称前缀
private final static String proxyClassNamePrefix = "$Proxy";
// 初始化时,代理被创建的个数为 0
private static long nextUniqueNumber = 0;
// 由于可能有多个客户同时使用 ProxyGenerator 创建代理对象,因此必须进行同步
// 此同步过程使代理被创建的数目唯一
private static Object nextUniqueNumberLock = new Object();
// 表示某个代理对象正在被创建
private static Object pendingGenerationMarker = new Object();
// 代理对象实例化时需要的的构造参数
private final static Class[] constructorParams ={ InvocationHandler.class };
// 类转载器的 cache
private static Map loaderToCache = new WeakHashMap();
// 所有已经被创建的代理对象的集合,每次要创建新的代理对象,都会先到该集合查找是否存在
// 这其实是一个代理对象的缓存
private static Map proxyClasses =Collections.synchronizedMap(new WeakHashMap());
protected InvocationHandler h; // 唯一的非静态的成员变量,主要用于 protected 构造器
protected Proxy(InvocationHandler h) { //protected 构造器,给继承提供了可能
this.h = h;
}
private Proxy() { } // 工具类,不能实例化,因此为私有构造器
// 使用特定的类加载器,加载某个类,从而得到此代理对象的 Class
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)throws IllegalArgumentException{
if (interfaces.length > 65535) { // 构造器太多,抛出异常
throw new IllegalArgumentException("interface limit exceeded");
}
Class proxyClass = null; // 初始化一个 Class
// 将 interface 的名字 collect interface names to use as key for proxy class cache */
String[] interfaceNames = new String[interfaces.length];
Set interfaceSet = new HashSet(); // 避免重复
for (int i = 0; i < interfaces.length; i++) {
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");
}
if (!interfaceClass.isInterface()) { // 不是接口抛出异常
throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface");
}
if (interfaceSet.contains(interfaceClass)) { // 已经存在抛出异常
throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());
}
interfaceSet.add(interfaceClass); // 不存在则放入 hashset 中
interfaceNames[i] = interfaceName; // 置换输入中的构造器
}
Object key = Arrays.asList(interfaceNames); // 将上面的数组转化为 List 对象
// 以上完成对构造器的处理
Map cache;
synchronized (loaderToCache) { // 同步化类装载器的 Cache
cache = (Map) loaderToCache.get(loader);
if (cache == null) {
cache = new HashMap(); // 该 Cache 以类装载器为 key , value 也为一个 Cache
loaderToCache.put(loader, cache);
}
}
synchronized (cache) {
do {
Object value = cache.get(key); // 该 Cache 以 Class 数组为 key 以 proxyClass 为 value
if (value instanceof Reference) {
proxyClass = (Class) ((Reference) value).get(); // 保存在 Cache 中的 value 为 Reference
}
if (proxyClass != null) { // 代理对象存在
return proxyClass; // 返回此 proxyClass
} else if (value == pendingGenerationMarker) {
try {
cache.wait(); // 其它线程正在创建代理对象,则本线程等待
} catch (InterruptedException e) { }
continue;
} else {
cache.put(key, pendingGenerationMarker);
break;
}
} while (true);
}
try {
String proxyPkg = null; // 代理对象所在的包
for (int i = 0; i < interfaces.length; i++) { // 遍历 Class 数组
int flags = interfaces[i].getModifiers(); // 得到 Class 的修饰符
if (!Modifier.isPublic(flags)) { //public 的修饰符
String >
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); //package 名称
if (proxyPkg == null) {
proxyPkg = pkg; //
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException( "non-public interfaces from different packages");
}
}
}//for
if (proxyPkg == null) {
proxyPkg = ""; // 默认包名
}
{
long num;
synchronized (nextUniqueNumberLock) { // 同步块
num = nextUniqueNumber++; // 每次递增 1
}
String proxyName = proxyPkg + proxyClassNamePrefix + num; // 名称为三者的组合
// 以下是创建 ProxyClass 的过程
byte[] proxyClassFile =ProxyGenerator.generateProxyClass(proxyName, interfaces);
// 上面是使用 ProxyGenerator 将指定名称代理类的 .class 文件转化为 byte 数组
// 在类加载器中进一步执行此 .class 文件,在 java 语言中经常称 java 为解释型语言
// 字节码就是被解释的中间代码,它是独立于平台的,其执行是在虚拟机上
// 有兴趣的朋友多研究研究编译原理、以及虚拟机的实现
// sun 已经将其 Compiler 和 VM 的源代码开源了,有能力可以研究研究
/ / 利用刚才产生的 byte 数组,使用类加载器产生此 ProxyClass
try {
使用类装载器,装载指定名称的代理类
proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
// 将新创建的 ProxyClass 放入 Chche 中
proxyClasses.put(proxyClass, null);
} finally {
synchronized (cache) {
if (proxyClass != null) {
cache.put(key, new WeakReference(proxyClass)); // 将此 Renference 放入 cache 中
} else {
cache.remove(key);
}
cache.notifyAll(); // 多线程的 wait/notify 机制
}
}
return proxyClass;
}