关于该设计模式需要解决的问题:
1、JAVA动态代理解决了什么问题?其实用场景是什么?
2、了解,如何使用,怎样将动态代理用于实际项目?
3、其原理是什么?底层代码是如何实现的?
问题1解答:
其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。使用场景有:日志与业务分离,在方法真正执行前先做一些判断或者执行后做一些处理等等,都是动态代理的实用场景。
问题2解答:
接口A,接口A的实现类B,类C继承InvocationHandler,实现invoke方法,该方法有参数(Object proxy, Method method, Object[] args) throws Throwable
代理类是由Proxy.getProxyClass()返回的类,Proxy.newProxyInstance()则返回代理类的实例
proxy是代理类的实例对象
method:在代理实例上执行的方法
args:在代理实例上执行method方法的参数
问题3解答:
重点在
getProxyClass方法
1、对代理类实现的接口做一些安全性检查:
实现的接口数最大长度为65535
=
2^16-1
个;
接口是否对参数classload可见
Class object是否为接口
接口是否重复
2、 /** maps a class loader to the proxy class cache for that loader */
private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache
= new WeakHashMap<>();
从loadToCach获取类装载器为对象关键词对应的缓存表,如果该缓存不存在则新建一个HashMap,放入缓存表,该HashMap存放的是该代理类实现的接口列表以及生成的动态代理类对象的引用,当代理类正在被创建的时候,它将通过<
接口名字列表,
pendingGenerationMarker>来进行保存,设置
pendingGenerationMarker标志是为了通知后来请求创建该接口名字列表的动态代理类实例该实例正在被创建,请等待其创建完成。待创建完成之后会notifyAll所有在等待的线程
3、创建动态代理类对象:
首先需要确定代理类所在的包,如果接口列表中的所有接口都是public的,该动态代理类的包则置空为空字符串,否则需要判断所有的接口列表是否在同一个包下,如果不是则会抛出
IllegalArgumentException异常,如果是,接口所在的包也就是代理类所在的包;
然后确定代理类的名称,名称采用$ProxyN的方式,N的值为nextUniqueNumber,该变量是同步的,由nextUniqueNumberLock监视
动态代理的动态代码由 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);来生成,该代码sun没有公开;
动态类的定义由
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);来定义,包括:类所在的加载器,动态代理类类名,动态代理的动态代码,
4、更新缓存表,如果成功则将代理类的类对象引用(new WeakReference<Class<?>>(proxyClass)
)更新至缓存表,否则则清除缓存表中的关键字(接口列表)对象
感觉也没有很好的解答开头提出的问题,有更好解答的或者有不对的地方欢迎大家指出,一起讨论!