借助于Java提供的Proxy和InvocationHandler,可以实现在运行时生成动态代理的功能,而动态代理对象可作为目标对象使用,而且增加了目标对象的功能。下面我们将要实现一个类似于JDK的动态代理。设计的UML类图如下。
下面笔者给出的实现方法。
1) 提供一个Dog接口。
public interface Dog { // info()方法声明 void info(); // run()方法声明 void run(); }
2) GunDog的类。
public class GunDog implements Dog { //info方法实现,仅仅打印一个字符串 public void info() { System.out.println("我是一只猎狗"); } //run方法实现,仅仅打印一个字符串 public void run() { System.out.println("我奔跑迅速"); } }
3) 下面提供一个TxUtil类,这个类通常称为拦截器,该类包含两个方法,分别是开始事务和提交事务。
public class TxUtil { // 第一个拦截器方法:模拟事务开始 public void beginTx() { System.out.println("=====模拟开始事务====="); } // 第二个拦截器方法:模拟事务结束 public void endTx() { System.out.println("=====模拟结束事务====="); } }
4) JDK动态代理的关键在于下面的MyInvokationHandler类,该类是一个InvocationHandler实现类,该实现类的invoke方法将会作为代理对象的方法实现。
public class MyInvokationHandler implements InvocationHandler { // 需要被代理的对象 private Object target; public void setTarget(Object target) { this.target = target; } // 执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法 public Object invoke(Object proxy, Method method, Object[] args) throws Exception { TxUtil tx = new TxUtil(); // 执行TxUtil对象中的beginTx()。 tx.beginTx(); // 以target作为主调来执行method方法 Object result = method.invoke(target , args); // 执行TxUtil对象中的endTx()。 tx.endTx(); return result; } }
5) 下面再为程序提供一个MyProxyFactory类,该对象专门为指定的target生成动态代理实例。
public class MyProxyFactory { // 为指定target生成动态代理对象 public static Object getProxy(Object target) throws Exception { // 创建一个MyInvokationHandler对象 MyInvokationHandler handler = new MyInvokationHandler(); // 为MyInvokationHandler设置target对象 handler.setTarget(target); // 创建并返回一个动态代理 return Proxy.newProxyInstance(target.getClass().getClassLoader() , target.getClass().getInterfaces(), handler); } }
6) 写个测试类。
public class Test { public static void main(String[] args) throws Exception { // 创建一个原始的GunDog对象,作为target Dog target = new GunDog(); // 以指定的target来创建动态代理 Dog dog = (Dog)MyProxyFactory.getProxy(target); // 调用代理对象的info()和run()方法 dog.info(); dog.run(); } }
7) 执行结果。
8) 执行步骤。
i. 创建TxUtil实例。
ii. 执行TxUtil实例的beginTx()方法。
iii. 使用反射以target作为调用执行info()方法。
iv. 执行TxUtil实例的endTx()方法。