内容简介:JAVA 动态代理学习记录
打算用 JAVA 实现一个简单的RPC框架,看完 RPC参考代码 之后,感觉RPC的实现主要用到了两个方面的JAVA知识:网络通信和动态代理。因此,先补补动态代理的知识。---多看看代码中写的注释
Java 代理模式与动态代理类
在动态代理中,首先定义一个接口,这个接口中声明的方法 是 真实类需要实现的,真实类实现该方法来提供具体的操作。
public interface Subject { public abstract void request(); }
public class RealSubject extends Subject{//具体实现类 public RealSubject(){ } public void request(){ System.out.println("From Real Subject"); } }
有了具体实现类,现在就需要代理类了,具体实现类在本例中为RealSubject.java ,它就是 被代理的类,即代理类 代理的“家伙”就是 具体实现类。
代理类需要实现 InvocationHandler 接口,为什么呢?先了解下JAVA动态代理中需要用到的一个接口:InvocationHandler 和 一个类: java.lang.reflect.Proxy
InvocationHandler接口中只有一个invoke方法,该方法需要三个参数:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ proxy:需要代理的真实类的对象 method:“待调用的真实对象的某个方法” args:调用该方法时需要的参数
InvocationHandler的作用就是将需要代理的类的对象作为构造函数的参数传给它,即传给代理类,这样代理类就知道自己代理的对象是什么了。 DynamicSubject implements InvocationHandler
//给构造方法传递不同的类型的 被代理的对象,就可以 实现 动态代理--即在运行时确定被代理的对象的类型 public DynamicSubject(Object obj){ sub = obj; }
同时,在客户端代码中进行方法调用时,会自动执行InvocationHandler接口的invoke方法,从而由InvocationHandler接口的invoke方法 中的 method.invoke() 再去执行真正的被代理类的方法。
method.invoke(sub, args);//调用 实际 的方法,调用被代理的对象的方法,即RealSubject.request()
看看JDK中java.lang.reflect.Method 中的invoke() 方法的定义:对带有指定参数的指定对象调用由此 Method
对象表示的底层方法。----即调用 指定对象 sub ,指定参数 args 所代表的方法。
再看看Proxy类的作用,Proxy类主要用来在Clinet代码中生成一个动态的对象。该对象调用方法来开始进行动态代理。
/* 第一个参数指定哪个 ClassLoader对象来加载我们的代理对象 * 第二个参数 为代理对象提供的接口是真实对象所实现的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了 * 第三个参数handler, 这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上,这样,当执行下条实际方法调用语句时,就可以 * 知道委托的是哪个InvocationHandler 了,进程就会自动执行该 InvocationHandler 的 invoke方法 */ Subject subject = (Subject)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), handler); /* * 当该语句执行时,它会委托到InvocationHandler 类中的 invoke方法,并执行 method.invoke()进行实际调用 * 注意:InvocationHandler.invoke()中有两条输出语句,运行Client后在控制台中看到了其输出结果,说明该方法被委托执行了 */ subject.request();
完整的动态代理类的实现代码如下:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicSubject implements InvocationHandler{ private Object sub;//被 代理的对象,它是一个Object类型的对象,说明,被 代理的对象是可以动态改变的 public DynamicSubject(){ } //给构造方法传递不同的类型的 被代理的对象,就可以 实现 动态代理--即在运行时确定被代理的对象的类型 public DynamicSubject(Object obj){ sub = obj; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ System.out.println("before calling " + method); /* * 在构造方法中获得了被代理的对象RealSubject sub */ method.invoke(sub, args);//调用 实际 的方法,调用被代理的对象的方法,即RealSubject.request() System.out.println("after calling " + method); return null; } }
完整的客户端实现代码如下:Client.java中的 subject.request(); 表示开始执行代理调用。可以从代码中看出,subject 对象是由 Proxy 动态生成的。
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) throws Exception{ RealSubject rs = new RealSubject();// 需要 被 代理的类,即客户端现在需要的代理一个类型为 RealSubject 的对象 /* * 注意,代理类的构造方法的参数为Object类型,说明它可以代理 任意类型的对象---即程序运行前DynamicSubject并不知道需要代理的对象 * AnOtherRealSubject anotherRs = new AnOtherRealSubject(); * InvocationHandler handler = new DynamicSubject(anotherRs); * */ InvocationHandler handler = new DynamicSubject(rs);// 代理类,将需要 被 代理的类 作为 代理类的构造 函数的参数传入 Class cls = rs.getClass(); /* * Class c = Proxy.getProxyClass(cls.getClassLoader(), cls.getInterfaces()); Constructor ct = c.getConstructor(new Class[]{InvocationHandler.class}); Subject subject = (Subject) ct.newInstance(new Object[]{handler}); */ /* * 第二个参数 cls.getInterfaces()... cls 是代表RealSubject类型的 Class对象,参考JDK中Class类的getInterfaces() *表明:newProxyInstance 知道动态生成的代理对象subject 需要实现哪些接口---需要实现的接口由getInterfaces()指定。 *而cls 是一个代表RealSubject类型的Class对象,RealSubject 实现了 Subject 接口,因此动态生成的subject 对象当然可以 *强制类型转换了。 */ Subject subject = (Subject)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), handler); /* * 当该语句执行时,它会委托到InvocationHandler 类中的 invoke方法,并执行 method.invoke()进行实际调用 * 注意:InvocationHandler.invoke()中有两条输出语句,运行Client后在控制台中看到了其输出结果,说明该方法被委托执行了 */ subject.request(); /* * 输出:com.sun.proxy.$Proxy0 * 这表明,subject 对象类型是 $Proxy0,而不是 Subject 或 InvocationHandler 类型 * 但是在 22行语句中,却可以将之进行强制类型转换,转成Subject类型 * 原因是:Proxy.newProxyInstance生成的是一个动态对象,即在JVM运行时生成的。在newProxyInstance()的第二个参数上,给它提供了一组接口 * 该代理对象就会实现这组接口,因此也就可以将该对象强制转化为这组接口中的任意一个 */ System.out.println(subject.getClass().getName()); } }
整个程序代码参考github: https://github.com/hapjin/JAVA/tree/master/dynamicProxy
本文转自hapjin博客园博客,原文链接:http://www.cnblogs.com/hapjin/,如需转载请自行联系原作者
以上所述就是小编给大家介绍的《JAVA 动态代理学习记录》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 使用 ES6 Proxy 代理的一些问题记录
- 记录一次windows server上,反向代理服务器的配置和使用
- 正向代理、反向代理和透明代理
- 正向代理与反向代理
- 反向代理与正向代理
- 正向代理与反向代理【总结】
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
An Introduction to Probability Theory and Its Applications
William Feller / Wiley / 1991-1-1 / USD 120.00
Major changes in this edition include the substitution of probabilistic arguments for combinatorial artifices, and the addition of new sections on branching processes, Markov chains, and the De Moivre......一起来看看 《An Introduction to Probability Theory and Its Applications》 这本书的介绍吧!