1、 什么是动态代理?
代理是基本的设计模式之一。它是你为了提供额外的或者不同的操作,而插入的用来代替“实际”的对象的对象。这些操作经常涉及与“实际”对象的通信,所以代理通常充当中间人的角色。Java动态代理的思想比代理更向前迈进了一步,因为它可以动态的创建代理并动态的处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定响应的政策。
2、 动态代理可以用来做什么?
动态代理的用途与装饰模式很相似,就是为了对某个对象进行增强。所有使用装饰者模式的案例都可以使用动态代理来替换。动态代理就是在运行时生成一个类,这个类会实现你指定的一组接口,而这个类没有.java文件,是在运行时生成的,你也不用去关心它是什么类型的,你只需要知道它实现了哪些接口即可。动态代理技术都是在框架中使用,例如:Struts1、Struts2、Spring和Hibernate中都使用了动态代理技术。所有学好动态代理对以后框架的学习很有好处!
3、 怎么使用动态代理?
3.1、静态方法Proxy.newProxyInstance()创建动态代理,方法需要三个参数,下面一一介绍
l ClassLoader loader:它是类加载器类型,今天不在这说它,以后专门开专题写它,我们只需要知道怎么可以获得它就可以了:XXX.class.getClassLoader()就可以获取到ClassLoader对象,没错,只要你有一个Class对象就可以获取到ClassLoader对象;
l Class[] interfaces:指定newProxyInstance()方法返回的对象要实现哪些接口,没错,可以指定多个接口
l InvocationHandler h:它是最重要的一个参数!它是一个接口!它的名字叫调用处理器!InvocationHandler接口只有一个方法,即invoke()方法!它是对代理对象所有方法的唯一实现。也就是说,无论你调用代理对象上的哪个方法,其实都是在调用InvocationHandler的invoke()方法。
3.2、InvocationHandler的invoke()方法,同样需要三个参数:
l Object proxy:代理对象,也就是Proxy.newProxyInstance()方法返回的对象,通常我们用不上它。
l Method method:表示当前被调用方法的反射对象,例如mi.fun1(),那么method就是fun1()方法的反射对象
l Object[] args:表示当前被调用方法的参数,当然mi.fun1()这个调用是没有参数的,所以args是一个零长数组。
最后,invoke()方法的返回值为Object类型,它表示当前被调用的方法的返回值。
4、 代码实例
interface waiter{
public void serve();
}
class MyWaiter implements waiter{
public void serve() {
System.out.println("服务。。。");
}
}
/**
* 目标:对服务生对象进行增强,在服务前后添加“您好”和“欢迎光临”!
* 手段:动态代理
* @author Jason
*
*/
public class MainApp1 {
/**
* @param args
*/
public static void main(String[] args) {
ClassLoader loader = MainApp1.class.getClassLoader();
Class[] c = {waiter.class};
waiter target = new MyWaiter();
MyInvocationHandler h = new MyInvocationHandler(target);
//创建动态代理,传递参数
waiter waiter1 = (waiter) Proxy.newProxyInstance(loader, c, h);
waiter1.serve();
}
}
class MyInvocationHandler implements InvocationHandler{
private waiter target;
public MyInvocationHandler(waiter target){
this.target = target;
}
/*
* 调用serve方法都会调用这个方法
*
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("您好。。。");
Object result = method.invoke(target, args);
System.out.println("欢迎下次光临!");
return result;
}
}