开发者学堂课程【Java 高级编程:动态代理设计模式】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/20/detail/394
动态代理设计模式
内容简介:
1.代理设计
2.代理方法
3.范例
1.代理设计
通过静态代理设计模式的缺陷可以发现,最好的做法是为所有功能一致的业务操作接口提供有统一的代理处理操作,而这可以通过动态代理机制来实现,但是在动态代理机制里面需要考虑到如下几点问题:
1)不管是动态代理类还是静态代理类都一定要接收真实业务实现子类对象。
动态代理机制,相当于有一个代理类,代理的是一堆业务接口。不管是静态代理还是动态代理,在整个程序的处理过程之中,一定要保证它能够接收所有的真实业务处理子类。
这里通过 proxy 来接收:
2)由于动态代理类不再与某一个具体的接口进行捆绑,所以应该可以动态获取类的接口信息。
动态代理最终返回给客户端的是一个接口代理对象,但是这个代理类不会与任何接口产生联系。
由于在每一个对象里面都可以通过反射获取接口,那么在整个操作过程之中,可以直接使用obj.getClass().getlnterfaces()
方法来获取所有可能需要用到的接口的操作对象。
客户端要想能够正常执行处理,就必须准备出一个接口代理对象,而接口代理对象是通过反射接口获得的,
如下图:
当取得接口对象之后都会有一个专门的系统类,系统类会根据接口对象和传过来的操作信息,做出自己的接口代理对象。系统将根据类加载器创建一个所谓的系统对象,当客户端通过代理对象进行操作的时候,本质上操作的就是接口。
在进行代理对象的创建和操作的过程之中,最重要的是 invocation Handler。Invocation Handler 实现的操作,就是在开发之中所做的代理方法控制。以上就是整个的代理设计模式的实现的结构,整个流程图如下:
在进行动态代理实现的操作之中,首先需要关注的就是一个 Invocation Handler 接口,这个接口规定了代理方法的执行。
这个代码由于要跨越到多个接口存在,所以方法名称由程序自己定义。
把 invocation handler 打开,接口如下:
public interface InvocationHandler {
/**
* 代理方法调用,代理主题类里面执行的方法最终都是此方法
* @param proxy要代理的对象
* @param method要执行的接口方法名称
* @param args 传递的参数
* @return 某一个方法的返回值
* @throws Throwable 方法调用时出现的错误继续向上抛出
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
2.代理方法
在进行动态代理设计的时候对于动态对象的创建是由JVM底层完成的,此时主要依靠的是 java.lang.reflect.Proxy 程序类,而这个程序类之中只提供有一个核心方法:
代理对象:
public static Object newProxyInstance(ClassLoader loader,Class<?>[]interfaces,InvocationHandler h)
-ClassLoader loader
:获取当前真实主题类的 ClassLoader;
- Class<?>[]interfaces
:代理是围绕接口进行的,所以一定要获取真实主题类的接口信息;
- InvocationHandler h:
代理处理的方法。
在整个代理操作中,第一个操作 Invocation handler,第二个核心类 proxy。
在主类进行操作处理的时候,一定要接收的是业务的真实实现类,proxy 根 据真实业务类对象创建代理对象。
主类进行操作用的是 proxy 返回的代理对象进行操作的,而这个代理对象最重要的特征是它的结构复合业务接口结构。
代理的对象不是直接去调用,它在调用的代理操作会找到 Invocation handler,方法 invoke()。
比如当调用对象的时候,业务接口中有个方法 fun():void,那么代理对象发出的指令也是对象.fun()。但是当调用时,会找到 invoke,而后 invoke 去调用业务接口方法,业务接口方法就是业务的实现子类,以上就是整体的操作流程。
3.范例
范例:实现动态代理机制
代码执行结果如下:
******【执行方法】
public abstract void cn.mldn.demo.IMessage.send()
【消息代理】进行消息发送通道的连接
【发送消息】www.mldn.cn
【消息代理】关闭消息通道。
如果你认真观察系统中提供的Proxy.newProxyInstance()
方法,就会发现该方法会使用大量的底层机制来进行代理对象的动态创建,所有的代理类是复合所有相关功能需求的操作功能类,它不再代表具体的接口,这样在处理的时候就必须依赖于类加载器与接口进行代理对象的伪造。