我们看具体代码:
public void pro() throws Exception{
Tank t = new Tank ();
InvocationHandler h = new TimeHandler( t);
Moveable m = (Moveable)Proxy.newProxyInstance(Moveable. class, h);
}
这个就是生产代理的代码,上篇看过了。
Moverable 接口:
public interface Moveable
{
public void move();
}
Moverable 接口有一个move方法。
Tank 类:
public class Tank implements Moveable{
@Override
public void move()
{
System. out.println( "Tank
moving ...");
try {
Thread. sleep(new Random().nextInt(10000));
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
这里很简单 就是有一个类叫tank 有个方法叫move可以随机sleep 时间。就是随机暂停一会。
我们现在希望把他通过动态代理,在这个方法前后添加代码,但是不改动原有代码,知道这个方法执行时间。就是知道每次它sleep多少时间。
我们先生成一个Handler 统一代理接口叫 invocationHandler 实现类叫 TimeHandler,就是用于添加时间的Handler。
接口类:
import java.lang.reflect.Method;
public interface InvocationHandler
{
public void invoke(Object o,Method m);
}
接口有个invoke方法。
TimeHandler实现类:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TimeHandler implements InvocationHandler
{
private Object target;
//构造函数
public TimeHandler(Object target)
{
super();
this. target = target;
}
@Override
public void invoke(Object o,
Method m) {
long start =
System. currentTimeMillis();//添加时间记录
System. out.println("start
time:"+ start);
try {
m.invoke( target);
} catch (Exception e)
{
e.printStackTrace();
}
long end =
System. currentTimeMillis();//添加时间记录
System. out.println( "time:" +
( end- start));
}
}
上面代码的意思:
这个实现类,实现了一个接口InvocationHandler,并重写了它的invoke方法 这个方法利用java反射机制将传入的m方法,属于Method类(反射中的Method类),对传进来的这个target对象的方法,添加记录时间的代码。
代码里面调用反射 Method类的invoke方法得到需要的被处理的对象的方法。这个m即传如的未知的方法。
这个例子中,即通过 m.invoke( target);调用tank对象的move方法。后面会调用。
注意说明:
重写的invoke方法和上面的反射函数的invoke不是一个方法。
重写的invoke 方法的第一个参数Object o在这个例子中没有用到。在java源代码里面有用到(先不用管)。
重写的invoke 方法的第二个参数就是Method 的m。
invoke会被循环调用,因为一个实体类中可以有很多方法,这个例子中target是tank,而tank对象下面只有一个move方法。
我们在invoke处理的时候,target就是指定的传递进来的对象。我们回到期初的代码就可以知道。
Tank t = new Tank ();
InvocationHandler h = new TimeHandler( t);
生成一个Tank 对象,把tank对象传进去。invoke tank这个target对象的m方法。
现在基本的使用的原理就完成了。
Moveable m = (Moveable)Proxy.newProxyInstance(Moveable. class, h);
当我们执行这条语句的时候,newProxyInstance方法 就会通过第一个参数Moveable.class 获得这个Tank对象 override的所有方法名,利用这些方法名会去找第二个参数h (就是TimeHandler)下面调用invoke方法,把这些方法名逐一循环放进invoke方法里面去。这样我们就把tank下面的方法在TimeHandler里面添加了代理。
最后newProxyInstance 帮我们生成对象返回给我们。