深入理解 jdk 动态代理的实现

本文详细解析了JDK如何利用Proxy.getProxyClass方法实现动态代理,包括初始化接口参数、查找或创建代理类缓存、代理对象名的产生以及最关键的一步——生成代理对象的过程。同时,解释了生成的代理类模板及其特性。

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

最近发现,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)
	}
	


}

关键还是通过继承来实现,也就意味着,被代理对象的父对象无法被动态代理。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值