什么是动态代理?
在介绍动态代理之前,首先我觉得有必要先理解下什么是静态代理,所谓的静态代理,就是程序运行前就已经存在编译好的代理类,具体的介绍和例子
可以看我之前的一篇博客介绍->java设计模式(四)--代理模式。如果这样,那么我们就很容易理解什么是动态代理了,所谓动态代理,就是代理类在
程序运行前并不存在,需要程序在运行时动态生成(无需手工编写代理类源码),这就是动态代理。
动态代理的原理
在展开动态代理的例子和代码讲解之前,请容许我花点时间啰嗦下它实现的机制或说原理,这个对于动态代理的理解至关重要。在java动态代理
机制中,有两个重要的类或是接口,一个是InvocationHandler(Interface),另一个是Proxy(Class),这两个类和接口是我们实现动态代理必须实现的。
InvocationHandler:每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们遇到代理对
象调用一个方法时,这个方法就会被转发为由InvocationHandler这个接口的Invoke方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个
方法invoke方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy: 指我们所代理的那个真实对象
method: 指的是我们所要调用真实对象的某个方法的Method对象
args: 指的是调用真实对象某个方法时接受的参数
newProxyInstance这个方法:
public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h) throws IllegalArgumentException
loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
OK,这两个接口都了解了以后,对后面动态代理的代码的理解就会显得非常easy了,我们通过下面的实例来看看我们动态代理是怎么玩的,例子还是
用王婆的例子来说明吧,比较生动:
首先,我们定义一个公共接口,王婆和潘金莲共有的:
package DynamicProxy;
/*
* 定义一种类型的女人,王婆和潘金莲都属于这个类型的女人
*/
public interface KindWoman
{
//这种女人能做什么事情呢?
public void makeEyesWithMan();//抛媚眼
public void happyWithMan();//和男人那个....
}
package DynamicProxy;
public class PanJinLian implements KindWoman
{
@Override
public void makeEyesWithMan()
{
System.out.println("潘金莲抛媚眼...");
}
@Override
public void happyWithMan()
{
System.out.println("潘金莲和男人在做那个...");
}
}
还提供在happy前,教你如何挑逗对方,happy后,还要打扫现场呀,不能光顾着happy吧,让武大郎看见怎么办:
package DynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/*
* 动态代理类,就是我在我另外一篇博客--代理模式中的王婆啦
*/
public class DynamicProxy implements InvocationHandler
{
// 这个就是我们要代理的真实对象(就是我另外一篇博客--代理模式中的潘金莲啦)
private Object kindWoman;
// 构造方法,给我们要代理的真实对象赋初值
public DynamicProxy(Object kindWoman)
{
this.kindWoman = kindWoman;
}
@Override
public Object invoke(Object object, Method method, Object[] args)
throws Throwable
{
System.out.println("\nThe invoking Method is:" + method.getName());
if(method.getName().equals("happyWithMan"))
{
// 在代理真实对象前我们可以添加一些自己的操作,是不是发现Spring中AOP的影子
System.out.println("happy之前,先挑逗。。。");
}
// 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(kindWoman, args);
if(method.getName().equals("happyWithMan"))
{
// 在代理真实对象后我们也可以添加一些自己的操作,是不是发现Spring中AOP的影子
System.out.println("happy完了,要打扫现场。。。");
}
return null;
}
}
package DynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client
{
public static void main(String[] args)
{
// 我们要代理的真实对象
KindWoman wanpo = new PanJinLian();
// 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandler handler = new DynamicProxy(wanpo);
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
* 第一个参数handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
KindWoman wangPo = (KindWoman)Proxy.newProxyInstance(
handler.getClass().getClassLoader(),
wanpo.getClass().getInterfaces(),
handler);
// 表面上看是王婆在跟西门庆抛媚眼,其实爽的是潘金莲
wangPo.makeEyesWithMan();
wangPo.happyWithMan();
}
}
The invoking Method is:makeEyesWithMan
潘金莲抛媚眼...
The invoking Method is:happyWithMan
happy之前,先挑逗。。。
潘金莲和男人在做那个...
happy完了,要打扫现场。。。
// 表面上看是王婆在跟西门庆抛媚眼,其实爽的是潘金莲
wangPo.makeEyesWithMan();
wangPo.happyWithMan();
这个 handler对象又接受了一个 RealSubject类型的参数,表示我要代理的就是这个真实对象,所以此时就会调用 handler 中的invoke方法去执行,
同时,在执行方法之前,我们还能做一些其他的事情:
public Object invoke(Object object, Method method, Object[] args)
throws Throwable
{
System.out.println("\nThe invoking Method is:" + method.getName());
if(method.getName().equals("happyWithMan"))
{
// 在代理真实对象前我们可以添加一些自己的操作,是不是发现Spring中AOP的影子
System.out.println("happy之前,先挑逗。。。");
}
// 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(kindWoman, args);
if(method.getName().equals("happyWithMan"))
{
// 在代理真实对象后我们也可以添加一些自己的操作,是不是发现Spring中AOP的影子
System.out.println("happy完了,要打扫现场。。。");
}
return null;
}
当我们通过代理对象来调用方法的时候,其实就是委托由其关联到的 handler 对象的invoke方法中来调用,并不是自己来真实调用,而是通
过代理的方式来调用的。
这就是java的动态代理机制。