java动态代理模式

java动态代理机制详解

Spring的核心AOP的原理就是java的动态代理机制。

在java的动态代理机制中,有两个重要的类或接口:

1.InvocationHandler(Interface):

  每一个动态代理类都必须要实现InvocatonHandler这个接口,并且每个代理类的实例都关联到一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由

InvocatonHandler这个接口的invoke方法来进行调用。

public Object invoke(Object proxy,Method method,Object[] args )throws Throwable
  { 
 }

proxy:代表我们所代理的那个真实对象;

method:只带我们所要调用真实对象的某个方法的Method对象;

args:指代的是调用真实对象某个方法时接受的参数。

2.Proxy(Class)

  这个类的作用就是用来动态的创建一个代理对象的类,它提供了许多方法,但是我们用的最多的就是newProxyInstance这个方法:

 1 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interface,InvocationHandler h)throws IllegalArgumentException 

loader:一个ClassLoder对象,定义了由那个ClassLoader对象来对生成的代理对象进行加载;

interface:一个Interface对象的数组,表示的是我将要给我的需要代理的对象提供一组什么借口,如果我提供了一组借口给他,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了;

h:一个InvocationHandler对象,表示的是当我这个代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上。

  

【代码清单--1】抽象对象角色:

 1 package com.huawei.subject;
 2 /**
 3  * 抽象对象角色
 4  * @author Administrator
 5  *
 6  */
 7 public interface Subject 
 8 {
 9     void rent();
10     void hello();
11 }

【代码清单--2】真实对象角色

 1 package com.huawei.subject.Impl;
 2 
 3 import com.huawei.subject.Subject;
 4 /**
 5  * 真实对象角色
 6  * @author Administrator
 7  *
 8  */
 9 public class RealSubject implements Subject 
10 {
11 
12     @Override
13     public void rent()
14     {
15         System.out.println("我想要出租my building");
16     }
17 
18     @Override
19     public void hello() 
20     {
21         System.out.println("租客你好");
22     }
23 
24 }

【代码清单--3】代理类

 1 package com.huawei.proxy;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 
 6 /**
 7  * 动态代理角色
 8  * @author Administrator
 9  *
10  */
11 public class DynamicProxy implements InvocationHandler 
12 {
13     //这个是我们要代理的真实对象
14     private Object subject;
15     //构造方法,给我们要代理的真实对象赋初值
16     public DynamicProxy(Object obj)
17     {
18         this.subject = obj;
19     }
20     
21 
22     @Override
23     public Object invoke(Object object, Method method, Object[] args)
24             throws Throwable 
25     {
26         //可以在代理真实对象之前进行一些自己的操作
27         System.out.println("Mrthod :"+method);
28         //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象的handler对象的invoke方法来进行调用
29         method.invoke(subject, args);
30         
31         //可以在代理真实对象之后进行一些自己的操作
32         
33         return null;
34     }
35 
36 }

【客户端】--测试类

 1 package com.huawei;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Proxy;
 5 
 6 import com.huawei.proxy.DynamicProxy;
 7 import com.huawei.subject.Subject;
 8 import com.huawei.subject.Impl.RealSubject;
 9 
10 public class Main {
11 
12     public static void main(String[] args) 
13     {
14         //我们要代理的真实对象
15         Subject realSubject = new RealSubject();
16         //我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
17         InvocationHandler handler = new DynamicProxy(realSubject);
18         /**
19          * 通过Proxy的newInstance方法来创建我们的代理对象
20          * 第一个参数handler.getClass().getClassLoader(),我们这里使用这个
21          * handler这个类的ClassLoader对象来加载我们的代理对象;
22          * 第二个参数realSubject.getClass().getInterface(),我们这里为代理对象提供的接口
23          * 是真实对象所实现的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了;
24          * 第三个参数handler,这里讲这个代理对象关联到上方的InvocationHandler这个对象上
25          */
26         
27         Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), 
28                                                     realSubject.getClass().getInterfaces(), 
29                                                     handler);
30         
31         System.out.println(subject.getClass().getName());
32         
33         subject.rent();
34         subject.hello();
35 
36     }
37 
38 }

【运行结果】

com.sun.proxy.$Proxy0
Mrthod :public abstract void com.huawei.subject.Subject.rent()
我想要出租my building
Mrthod :public abstract void com.huawei.subject.Subject.hello()
租客你好

  通过Proxy.newInstance创建的代理对象是在JVM运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行时动态生成的一个对象,

并且明明方式都是这样的形式,以$开头,proxy为重,最后一个数字表示对象的标号。

subject.rent();
subject.hello();

  这里是通过代理对象来调用实现的那种接口中的方法,这个时候程序就会跳转到由这个代理对象关联到的handler中的invoke方法去执行,而我们

的这个handler对象又接受一个RealSubject类型的参数,表示我要代理的就是这个真实对象,所以此时就会调用handler中invoke方法去执行。

  由结果可知,也证明了当我们通过代理对象来调用方法的时候,实际就是委托有其关联到的handler对象的invoke方法中来调用,并不是自己真实调用,而是通过代理的方法来调用的。

原文地址:https://www.cnblogs.com/lthIU/p/5837737.html