设为首页 加入收藏

TOP

Java动态代理深入解析(四)
2017-02-08 08:16:41 】 浏览:372
Tags:Java 动态 代理 深入 解析
);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }


? ? ? ? ? ? if (proxyPkg == null) {? ? // if no non-public proxy interfaces,
? ? ? ? ? ? ? ? proxyPkg = "";? ? ? ? ? // use the unnamed package
? ? ? ? ? ? }


? ? ? ? ? ? {
? ? ? ? ? ? ? ? /*
? ? ? ? ? ? ? ? * Choose a name for the proxy class to generate.
? ? ? ? ? ? ? ? */
? ? ? ? ? ? ? ? long num;
? ? ? ? ? ? ? ? synchronized (nextUniqueNumberLock) {
? ? ? ? ? ? ? ? ? ? num = nextUniqueNumber++;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? String proxyName = proxyPkg + proxyClassNamePrefix + num;  //生成代理类的名字,proxyPkg是上面确定下来的代理类所在的包名,proxyClassNamePrefix是写死的字符串“$Proxy”,num是一个全局唯一的long型数字,从0开始累积,每次生成新的代理类就+1,从这里也能看出生成的动态代理类的数量不能超过Long.maxValue
? ? ? ? ? ? ? ? /*
? ? ? ? ? ? ? ? * Verify that the class loader hasn't already
? ? ? ? ? ? ? ? * defined a class with the chosen name.
? ? ? ? ? ? ? ? */


? ? ? ? ? ? ? ? /*
? ? ? ? ? ? ? ? * Generate the specified proxy class.
? ? ? ? ? ? ? ? */
? ? ? ? ? ? ? ? byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
? ? ? ? ? ? ? ? ? ? proxyName, interfaces);  //生成一个以proxyName为类名的,实现了Interfaces里所有接口的类的字节码
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? proxyClass = defineClass0(loader, proxyName,
? ? ? ? ? ? ? ? ? ? ? ? proxyClassFile, 0, proxyClassFile.length);  //加载生成的类
? ? ? ? ? ? ? ? } catch (ClassFormatError e) {
? ? ? ? ? ? ? ? ? ? /*
? ? ? ? ? ? ? ? ? ? * A ClassFormatError here means that (barring bugs in the
? ? ? ? ? ? ? ? ? ? * proxy class generation code) there was some other
? ? ? ? ? ? ? ? ? ? * invalid aspect of the arguments supplied to the proxy
? ? ? ? ? ? ? ? ? ? * class creation (such as virtual machine limitations
? ? ? ? ? ? ? ? ? ? * exceeded).
? ? ? ? ? ? ? ? ? ? */
? ? ? ? ? ? ? ? ? ? throw new IllegalArgumentException(e.toString());
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? // add to set of all generated proxy classes, for isProxyClass
? ? ? ? ? ? proxyClasses.put(proxyClass, null);


? ? ? ? } finally {
? ? ? ? ? ? /*
? ? ? ? ? ? * We must clean up the "pending generation" state of the proxy
? ? ? ? ? ? * class cache entry somehow.? If a proxy class was successfully
? ? ? ? ? ? * generated, store it in the cache (with a weak reference);
? ? ? ? ? ? * otherwise, remove the reserved entry.? In all cases, notify
? ? ? ? ? ? * all waiters on reserved entries in this cache.
? ? ? ? ? ? */
       //创建成功,则将cache中该key的pendingGenerationMarker替换为实际的代理类的弱引用,否则也要清除pendingGenerationMarker标记;不管是否成功,都要执行cache.notifyAll(),让其它要创建相同代理类并且执行了cache.wait()的线程恢复执行。
? ? ? ? ? ? synchronized (cache) {
? ? ? ? ? ? ? ? if (proxyClass != null) {
? ? ? ? ? ? ? ? ? ? cache.put(key, new WeakReference>(proxyClass));
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? cache.remove(key);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? cache.notifyAll();
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return proxyClass; //最后返回代理类Class
? ? }


?到这里,我们已经把动态代理的java源代码都解析完了,现在思路就很清晰了:


Proxy.newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h) 方法简单来说执行了以下操作:


1.生成一个实现了参数interfaces里所有接口且继承了Proxy的代理类的字节码,然后用参数里的classLoader加载这个代理类。


2.使用代理类父类的构造函数 Proxy(InvocationHandler h)来创造一个代理类的实例,将我们自定义的InvocationHandler的子类传入。


3.返回这个代理类实例,因为我们构造的代理类实现了interfaces(也就是我们程序中传入的subject.getClass().getInterfaces())里的所有接口,因此返回的代理类可以强转成Subject类型来调用接口中定义的方法。


现在我们知道了用Proxy.newProxyInstance()返回的subjectProxy可以成功强转成Subject类型来调用接口中定义的方法了,那么在调用方法后,代理类实例怎么进行处理的呢,这就需要看一下代理类的源码了。但是代理类是程序动态生成字节码加载的,怎么看源码呢?没关系,可以在main方法中加入System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"),这样就会把生成的代理类Class文件保存在本地磁盘上,然后再反编译可以得到代理类的源码:


package common;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;


public final class $Proxy0 exten

首页 上一页 1 2 3 4 5 下一页 尾页 4/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇从JVM的角度来看单例模式 下一篇Java虚拟机字节码执行引擎

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目