动态代理(2)

本文介绍如何使用Java动态代理为Tank类的move方法添加执行时间记录,通过实现InvocationHandler接口并利用Proxy.newProxyInstance方法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们看具体代码:
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 帮我们生成对象返回给我们。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值