借助于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()方法。