您的位置:首页 > 编程语言 > Java开发

java动态代理机制

2016-07-15 09:22 417 查看
  Java动态代理中有两个重要的接口跟类,即 InvoctionHandler(Interface)、DynamicProxy(class),这个接口跟类使我们应用动态代理时必须要用的。每一个动态代理类都必须去实现 InvoctionHandler 这个接口,而且每个代理类的实例都必须关联一个 Hanlder 通过代理对象调用被代理对象中的方法时,其实是代理对象委托 InvoctionHandler 中的 invoke() 方法去调用被代理对象中的方法。invoke()方法的语法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
其中三个参数的具体说明如下:
proxy:  指代我们所代理的那个真实对象
method:  指代的是我们所要调用真实对象的某个方法的Method对象
args:  指代的是调用真实对象某个方法时接受的参数
Proxy 这个类提供了许多方法,其中我们最常用到的是 newProxyInstance 这个方法,这个方法作用就是得到一个动态代理的实例:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上我们来看一个例子,手机按我们定义了一个 Subject 接口,这个接口声明了真实对象和代理对象的共同接口,作用是在任何可以使用真实对象的时候都可以使用代理对象:package proxy1;public interface Subject {void rent();void Hello(String str);}接下来要定义一个真实类来实现这个接口:package proxy1;public class RealSubject implements Subject {@Overridepublic void rent() {System.out.println("I want to rent a house!");}@Overridepublic void Hello(String str) {System.out.println("Hello " + str);}}这个真实类中具体实现了抽象接口中定义的方法。接下来就要定义动态代理类了,这个动态代理类必须实现 InvocationHandler 接口:package proxy1;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class DynamicProxy implements InvocationHandler {private Object subject;public DynamicProxy(Object subject) {this.subject = subject;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before rent a house,you need to know the proxyObject name.");System.out.println("The proxyObject name is: " + method.getName());method.invoke(subject, args);System.out.println("Now you can live in your new house.");return null;}} 代理类中含有对真实类的引用,从而可以在任何时刻操作真实对象。代理类提供一个与真实类相同的接口,以便在任何时候都可以代理真实类,控制对真是类引用,负责在需要的时候创建真实类对象或者删除真实类对象。代理类通常在将客户端调用传递给真实类之前或者之后,都要执行特定操作,比如日志记录等等,而不是单纯地将调用传递给真实类。最后我们还要定义一个客户端:package proxy1;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;public class Client {public static void main(String[] args) {Subject subject=new RealSubject(); //创建一个真实对象的引用InvocationHandler handler=new DynamicProxy(subject); //将真实对象的引用传递给代理对象Subject str=(Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(),subject.getClass().getInterfaces(), handler); //代理对象调用真实对象的方法,通过 Proxy.newProxyInstance 创建的//代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,//也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,//以$开头,proxy为中,最后一个数字表示对象的标号。str.rent();str.Hello("Tom");}}控制台输出:Before rent a house,you need to know the proxyObject name.The proxyObject name is: rentI want to rent a house!Now you can live in your new house.Before rent a house,you need to know the proxyObject name.The proxyObject name is: HelloHello TomNow you can live in your new house.str.rent();str.Hello("Tom");这里是通过代理对象来调用实现的那种接口中的方法,这个时候程序就会跳转到由这个代理对象关联到的 handler 中的invoke方法去执行,而我们的这个 handler 对象又接受了一个 RealSubject类型的参数,表示我要代理的就是这个真实对象,所以此时就会调用 handler 中的invoke方法去执行:public Object invoke(Object object, Method method, Object[] args)throws Throwable{//  在代理真实对象前我们可以添加一些自己的操作System.out.println("Before rent a house,you need to know the proxyObject name.");System.out.println("The proxyObject name is: " + method.getName());// 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用method.invoke(subject, args);//  在代理真实对象后我们也可以添加一些自己的操作System.out.println("Now you can live in your new house.");return null;}
调用的就是我们的Subject接口中的两个方法,这也就证明了当我通过代理对象来调用方法的时候,实际就是委托由其关联到的 handler 对象的invoke方法中来调用,并不是自己来真实调用,而是通过代理的方式来调用的。
                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java