java代理模式-动态代理学习
2016-11-04 00:21
302 查看
尊重原创:http://blog.csdn.net/bingju328/article/details/53028729
那有木有办法在程序运行的时候动态的创建代理类呢?肯定有了,那就是本文将要了解的动态代理技术。为了更好的理解,动态代理要和上一篇的静态代理对比着学习,所以例子依然是在上一篇 文章例子的基础下修改的,不太熟悉的静态代理的同学可以先看一下上一篇 java代理模式-静态代理学习。
动态代理主要涉及的类:
Proxy : 这个类提供了动态创建代理对象的方法,它也是所有通过它的方法创建的代理对象的父类.
主要方法有:public static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h);
第一个参数是被代理的对象的类加载器 。
第二个参数是被代理的对象实现的接口集合 。
第三个参数是 InvocationHandler接口的一个实现类,当被代理的具体对象的方法被调用的时候,会调用InvocationHandler的实现类中的invoke()方法。
InvocationHandler:一个代理实例调用处理的接口。
主要方法有:public Object invoke(Object proxy, Method method, Object[] args);
第一个参数是被调用方法的代理实例。
第二个参数是需要代理的方法(即代理实例中要调用的方法)。
第三个参数是第二个参数 method 中所需传入的参数。
InvocationHandler、Proxy、被代理的目标对象三者的关系:
通过Proxy方法返回一个目标对象的代理实例,这个代理实例动态的实现了目标对象所实现的接口,同时也持有InvocationHandler的一个实现类的引用,当代理实例调用目标对象中的方法的时候,这个方法的调用在运行时被编码并且委派给 InvocationHandler的一个实现类中的invoke()方法(就是代理实例调用代理方法的时候其实是调用的InvocationHandler中的invoke()方法),由invoke() 来统一的处理目标对象对方法的调用。
(房天下公司房子的房主)第一个具体主题
(房天下公司)第一个代理对象角色
(链家公司房子的房主)第二个具体主题
(链家公司)第二个代理对象角色
客户端类
上面这个客户端类是静态代理的操作调用,对目标对象FTXRentSubject、LjRentSubject ,我们需要新建两个代理类 ProxyFTXSubject、ProxyLjSubject 来分别代理不同的目标对象,就像文章开头所说那样,如果目标对象有10个20个,那我们需新建10个20个代理类来分别代理不同的目标对象,这样势必会导致代码冗余,所以才需要动态代理的。
下面是动态代理的相关类:
InvocationHandler接口的实现类
动态代理的客户端操作类
上面这个客户端类是动态代理的操作调用,对目标对象FTXRentSubject、LjRentSubject ,只需用同一个方法Proxy.newProxyInstance();这个方法返回一个接口RentSubject 的一个实现类,当代理实例调用目标对象中的rent()方法的时候,这个方法的调用在运行时被编码并且委派给 InvocationHandler的一个实现类(RealInvocationHandler)中的invoke()方法(就是代理实例调用代理方法rent()的时候其实是调用的InvocationHandler中的invoke()方法),由invoke() 来统一的处理目标对象对方法的调用。
前言:
通过上一篇 java代理模式-静态代理学习 对静态代理的学习,我们知道静态代理模式中的每个类在编译后就会生成一个class文件,即代理类所实现的方法在编译完成后就都被固定了。如果用这种代理方式,当我们在代理多个对象时,就需要为每个实体类都编写一个新的代理类,这样势必会导致项目中的类越来越多,比如说:在 java代理模式-静态代理学习 一篇中存在的 房天下的房东类:FTXRentSubject(具体主题角色)所对应的代理类为房天下公司类:ProxyFTXSubject(代理对象角色) , 此时若添加一个新的 链家的房东类:LjRentSubject(具体主题角色)必须为这个类新写一个代理类 链家公司类:ProxyLjSubject(代理对象角色),这个时候有人说了,这还好,就加一个新的代理类我能接受啊。那如果需求是有100个具体主题需要被代理呢~~~是不是要疯了。。~_~|||。那有木有办法在程序运行的时候动态的创建代理类呢?肯定有了,那就是本文将要了解的动态代理技术。为了更好的理解,动态代理要和上一篇的静态代理对比着学习,所以例子依然是在上一篇 文章例子的基础下修改的,不太熟悉的静态代理的同学可以先看一下上一篇 java代理模式-静态代理学习。
动态代理介绍:
动态代理可以根据具体主题对象在运行时动态的创建代理类,即一个代理类可以代理多个不同的具体主题对象。动态代理主要涉及的类:
Proxy : 这个类提供了动态创建代理对象的方法,它也是所有通过它的方法创建的代理对象的父类.
主要方法有:public static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h);
第一个参数是被代理的对象的类加载器 。
第二个参数是被代理的对象实现的接口集合 。
第三个参数是 InvocationHandler接口的一个实现类,当被代理的具体对象的方法被调用的时候,会调用InvocationHandler的实现类中的invoke()方法。
InvocationHandler:一个代理实例调用处理的接口。
主要方法有:public Object invoke(Object proxy, Method method, Object[] args);
第一个参数是被调用方法的代理实例。
第二个参数是需要代理的方法(即代理实例中要调用的方法)。
第三个参数是第二个参数 method 中所需传入的参数。
InvocationHandler、Proxy、被代理的目标对象三者的关系:
通过Proxy方法返回一个目标对象的代理实例,这个代理实例动态的实现了目标对象所实现的接口,同时也持有InvocationHandler的一个实现类的引用,当代理实例调用目标对象中的方法的时候,这个方法的调用在运行时被编码并且委派给 InvocationHandler的一个实现类中的invoke()方法(就是代理实例调用代理方法的时候其实是调用的InvocationHandler中的invoke()方法),由invoke() 来统一的处理目标对象对方法的调用。
实现代码如下:
抽象主题/** * 抽象主题,定义主要功能的接口 * 功能:rent() 租房 * */ public interface RentSubject { public String rent(String operation); }
(房天下公司房子的房主)第一个具体主题
/** * (房天下公司房子的房主)具体主题,是对抽象主题的实现 * */ public class FTXRentSubject implements RentSubject { public String rent(String operation) { //房主具体的操作 System.out.println("FTXRentSubject--"+operation); return operation; } }
(房天下公司)第一个代理对象角色
/** * (房天下公司)代理对象角色,替目标对象(即具体主题,{@link FTXRentSubject})来做相关的操作 * */ public class ProxyFTXSubject implements RentSubject { private FTXRentSubject ftxRentSubject; public ProxyFTXSubject(FTXRentSubject ftxRentSubject) { this.ftxRentSubject = ftxRentSubject; } public String rent(String operation) { //房东租房前的操作 System.out.println(operation+"-before"); //调用目标对象的方法来操作 //此调用方式实质上也是类ProxyFTXSubject和FTXRentSubject之间的一种"组合方式" 的调用 //主要作用是:在需求变更的时候操作代理对象ProxyFTXSubject而不用改变FTXRentSubject类 //从而达到了解耦的效果 ftxRentSubject.rent(operation); //房东租房后的操作 System.out.println(operation+"-after"); return operation; } }
(链家公司房子的房主)第二个具体主题
/** * (链家公司房子的房主)具体主题,是对抽象主题的实现 * */ public class LjRentSubject implements RentSubject { public String rent(String operation) { //房主具体的操作 System.out.println("LjRentSubject--"+operation); return operation; } }
(链家公司)第二个代理对象角色
/** * (链家公司)代理对象角色,替目标对象(即具体主题,{@link LjRentSubject})来做相关的操作 * */ public class ProxyLjSubject implements RentSubject { private LjRentSubject ljRentSubject; public ProxyLjSubject(LjRentSubject ljRentSubject) { this.ljRentSubject = ljRentSubject; } public String rent(String operation) { //房东租房前的操作 System.out.println(operation+"-before"); //调用目标对象的方法来操作 //此调用方式实质上也是类ProxyFTXSubject和FTXRentSubject之间的一种"组合方式" 的调用 //主要作用是:在需求变更的时候操作代理对象ProxyFTXSubject而不用改变FTXRentSubject类 //从而达到了解耦的效果 ljRentSubject.rent(operation); //房东租房后的操作 System.out.println(operation+"-after"); return operation; } }
客户端类
/** * 客户端类 * */ public class Client { public static void main(String[] args){ //房天下的房东客户不能直接找房东租 FTXRentSubject ftxRentSubject = new FTXRentSubject(); ProxyFTXSubject proxyFTXSubject = new ProxyFTXSubject(ftxRentSubject); //客户给房天下公司发出需求:租房子 proxyFTXSubject.rent("房天下客户租房子"); //链家的房东客户不能直接找房东租 LjRentSubject ljRentSubject = new LjRentSubject(); ProxyLjSubject proxyLjSubject = new ProxyLjSubject(ljRentSubject); proxyLjSubject.rent("链家客户租房子"); //从现在开始所有所有客户都要办理居住证才可以租房子 proxyFTXSubject.rent(new HandleJuZhuPermit("房天下客户租房子").handlePermit("先办理居住证")); } }
上面这个客户端类是静态代理的操作调用,对目标对象FTXRentSubject、LjRentSubject ,我们需要新建两个代理类 ProxyFTXSubject、ProxyLjSubject 来分别代理不同的目标对象,就像文章开头所说那样,如果目标对象有10个20个,那我们需新建10个20个代理类来分别代理不同的目标对象,这样势必会导致代码冗余,所以才需要动态代理的。
下面是动态代理的相关类:
InvocationHandler接口的实现类
/** * InvocationHandler 这个接口是被Proxy 实例实现的接口,通过Proxy 把每个被代理的 * 对象和InvocationHandler联系起来,当被代理对象的方法被调用的时候会调用 被实现的{@code invoke} * 方法。 * 此类就是InvocationHandler的类 * */ public class RealInvocationHandler implements InvocationHandler{ // private RentSubject rentSubject; private Object object1; public RealInvocationHandler(Object rentSubject) { this.object1 = rentSubject; } /** * @param Object proxy 被代理的角色对象 * * @param Method method 被代理的角色对象将要调用的方法 * * @param Object[] args 被代理的角色对象调用的方法的参数 集合 * */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("proxy:"+proxy.getClass().getName()); System.out.println("method:"+method.getName()); System.out.println(((args != null && args.length > 0) ? args[0] : "租房子-")+"before"); Object object = method.invoke(object1, args); System.out.println(((args != null && args.length > 0) ? args[0] : "租房子-")+"after"); return object; } }
动态代理的客户端操作类
/** * 客户端类 * */ public class Client { public static void main(String[] args){ //动态代理FTXRentSubject目标对象 System.out.println("动态代理--------------"); FTXRentSubject ftxRentSubject = new FTXRentSubject(); /** * newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) * * ClassLoader loader 被代理的对象的类加载器 * Class<?>[] interfaces 被代理的对象实现的接口集合 * InvocationHandler h 当被代理对象的方法被调用的时候会调用 被实现的InvocationHandler中的 invoke()方法。 * 根据传入的参数返回一个动态生成的 代理类实例对象 * @return * */ RentSubject ftxsubject = (RentSubject) Proxy.newProxyInstance(ftxRentSubject.getClass().getClassLoader(), ftxRentSubject.getClass().getInterfaces(), new RealInvocationHandler(ftxRentSubject)); //调用此方法实质上是调用了 实现的InvocationHandler中的 invoke()方法 ftxsubject.rent("房天下客户租房子"); //动态代理LjRentSubject目标对象 System.out.println("动态代理--------------"); LjRentSubject ljRentSubject = new LjRentSubject(); RentSubject ljsubject = (RentSubject) Proxy.newProxyInstance(ljRentSubject.getClass().getClassLoader(), ljRentSubject.getClass().getInterfaces(), new RealInvocationHandler(ljRentSubject)); //调用此方法实质上是调用了 实现的InvocationHandler中的 invoke()方法 ljsubject.rent("链家客户租房子"); } }
上面这个客户端类是动态代理的操作调用,对目标对象FTXRentSubject、LjRentSubject ,只需用同一个方法Proxy.newProxyInstance();这个方法返回一个接口RentSubject 的一个实现类,当代理实例调用目标对象中的rent()方法的时候,这个方法的调用在运行时被编码并且委派给 InvocationHandler的一个实现类(RealInvocationHandler)中的invoke()方法(就是代理实例调用代理方法rent()的时候其实是调用的InvocationHandler中的invoke()方法),由invoke() 来统一的处理目标对象对方法的调用。
后记:
以上就是我学习动态代理模式的相关记录,设计模式只是整个程序大厦中的基础,基础牢固了,再来了解一些基于相应的设计模式编写的开源框架就会比较容易了。比如:了解完了动态代理,这个时候再来看Retrofit的源码就相对容易了,其实Retrofit框架主要的思想就是通过动态的代理每个ApiService的接口,然后在InvocationHandler中的invoke()方法中做相应的处理。这理只做简单的说明,具体分析放在后续的笔记中进行说明。相关文章推荐
- java动态代理学习(一)
- 学习:java设计模式—动态代理模式
- java代理模式--动态代理
- java的动态代理学习总结
- JAVA代理模式与动态代理模式
- [原]spring学习笔记8.2动态代理基础
- java动态代理学习
- java 动态代理学习
- 学习动态代理的总结
- java 动态代理深度学习
- 设计模式学习——动态代理实现C#动态调用WebService(附源码)
- Java动态代理学习文章(一)
- java动态代理的学习
- java 之 动态代理学习示例
- 学习动态代理stepbystep(3)
- aop原理学习——动态代理
- java 动态代理学习(Proxy,InvocationHandler)
- 学习动态代理stepbystep(1)
- 动态代理实践的学习笔记
- 学习Spring必学的Java基础知识(2)----动态代理