最近发现,java框架中大量使用了 动态代理。 原来只是会简单的使用,但是今天想深入研究下jdk是如何实现的。
一个比较靠谱的博客:http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html
至于Proxy 怎么用,在这里就不赘述了。关键是想说说 jdk怎么实现的。
主要想讲讲 这个方法
Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces)
分几个步骤:
一、初始化接口参数
String[] interfaceNames = new String[interfaces.length];
//用来检查接口是否重复
Set interfaceSet = new HashSet();
//做一些验证,同时将 interfaceNames 装满
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");
}
//判断是接口
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);
//将接口名称装入数组
interfaceNames[i] = interfaceName;
}
二、通过类装载器,来找到当前是否有代理类Map的缓存。避免再次创建。 weakHashMap 是jdk 里的弱键map.直接和垃圾回器挂钩
Object key = Arrays.asList(interfaceNames);
//通过class loader 来查找或者创建代理类
//loaderToCache 是一个 WeakHashMap() ,专门用来维护 类加载器和对应的代理类缓存
Map cache;
synchronized (loaderToCache) {
cache = (Map) loaderToCache.get(loader);
if (cache == null) {
cache = new HashMap();
loaderToCache.put(loader, cache);
}
}
三、针对具体的接口名称集合,来找缓存
//主要是从缓存中查找是否代理对象。
//如果没有代理类对象,判断是否有别的线程正在生成当前代理独享
synchronized (cache) {
do {
//以接口名称数组为key,从缓存中代理类
Object value = cache.get(key);
//判断是接口
if (value instanceof Reference) {
proxyClass = (Class) ((Reference) value).get();
}
//找到了直接返回
if (proxyClass != null) {
return proxyClass;
}
//没找到,pendingGenerationMarker 是一个标记对象,用来表示当前代理对象是否正在产生
else if (value == pendingGenerationMarker) {
// 代理对象正在生成,线程阻塞。
try {
cache.wait();
} catch (InterruptedException e) {
}
continue;
} else {
//当前没有代理对象正在创建,标记该接口列表的代理对象正在创建
cache.put(key, pendingGenerationMarker);
break;
}
} while (true);
}
四、代理对象名的产生
//针对一些非public 的接口,得到代理类生成的包路径
try {
String proxyPkg = null; // package to define proxy class in
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)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
//如果全部是public 接口
if (proxyPkg == null) {
proxyPkg = "";
}
{
long num;
//当前对象代理对象统一数量管理
synchronized (nextUniqueNumberLock) {
num = nextUniqueNumber++;
}
//代理对象新的名称
String proxyName = proxyPkg + proxyClassNamePrefix + num;
四、最关键的一步,生成代理对象
//通过 ProxyGenerator 得带代理类的class 的二进制数据
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
try {
//调用本地方法,然后直接返回
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
proxyClasses.put(proxyClass, null);
} finally {
//别忘了,最终要释放还要告知别的线程,代理对象创建完毕。
synchronized (cache) {
if (proxyClass != null) {
cache.put(key, new WeakReference(proxyClass));
} else {
cache.remove(key);
}
//通知阻塞线程
cache.notifyAll();
}
}
return proxyClass;
ok,这个最主要的方法讲完了。
想说明下,其实jdk自带的动态代理生成的代理类,无非就是如下格式
public final class ProxySubject(被代理的类) extends Proxy implements interface(接口集合)
{
//自己定义的InvocationHandler
InvocationHandler invocationHandler;
//构造方法,
public ProxySubject(InvocationHandler invocationHandler){
this.invocationHandler = invocationHandler;
}
//接口的方法
public void method{
invocationHandler.invoke(this, method(被调用方法对象), null)
}
}
关键还是通过继承来实现,也就意味着,被代理对象的父对象无法被动态代理。