...续前一篇
二、动态代理
动态代理与静态代理相相比,最大的好处就是接口中声明的所有方法都被转移到一个集中的方法中进行处理(即 invoke 方法)。这样做的好处是,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样,在每一个方法里都进行中转。
但是,动态代理类只能代理接口,代理类都需要实现 InvocationHandler 类,并覆写其 invoke() 方法。该invoke() 方法就是所有方法被代理后需要调用的方法,该 invoke() 方法返回的值是被代理接口的一个实现类。
还是以前面的服务生例子为例,创建以下动态代理类:
/**
* 服务员动态代理类
*
* @author ZHULX
*
*/
public class DynamicProxyWaiter implements InvocationHandler {
// 持有被代理的接口对象
private Object waiter;
/**
* 绑定被代理的对象,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法被调用时,执行 invoke 方法。
*
* @param waiter
* 被代理的实现类对象
* @return返回代理后的对象
*/
public ObjectbindRelation(Object waiter) {
this.waiter = waiter;
ObjectproxyWaiter = Proxy.newProxyInstance(waiter.getClass().getClassLoader(),waiter.getClass().getInterfaces(),this);
return proxyWaiter;
}
/**
* 所有方法的代理方法
*
* @param proxy
* 代理后的对象
* @param method
* 被代理对象即将被调用的方法
* @param args
* 即将被调用方法的参数
* @return返回执行后的代理对象
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Objectresult = waiter;
if (method.getName().endsWith("Welcome")) {
System.out.println("****** 向顾客行90°度鞠躬礼 ******");
result = method.invoke(waiter, args);
}else if (method.getName().endsWith("Goodbye")) {
System.out.println("****** 向顾客行45°度鞠躬礼 ******");
result = method.invoke(waiter, args);
}
return result;
}
}
最后,我再重新创建一个测试类:
/**
* 测试类
*
* @author ZHULX
*
*/
public class Test {
public static void main(String[] args) {
// 被代理的对象
IWaiterwaiter = new WaiterImpl();
System.out.println("未代理前的执行结果:");
waiter.sayWelcome();
waiter.sayGoodbye();
// 代理对象
DynamicProxyWaiterhandler = new DynamicProxyWaiter();
IWaiterproxyWaiter = (IWaiter) handler.bindRelation(waiter);
// 执行代理对象的方法
System.out.println("\n代理后的执行结果:");
proxyWaiter.sayWelcome();
proxyWaiter.sayGoodbye();
}
}
如果一切正常,输出应该如下所示:
未代理前的执行结果:
****** 您好,欢迎光临! ******
****** 您慢走,欢迎再次光临! ******
代理后的执行结果:
****** 向顾客行90°度鞠躬礼 ******
****** 您好,欢迎光临! ******
****** 向顾客行45°度鞠躬礼 ******
****** 您慢走,欢迎再次光临! ******
因此,不难发现,我们可以灵活地在委托类执行某方法前后加入任意的程序逻辑。