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方法中来调用,并不是自己真实调用,而是通过代理的方法来调用的。