上一篇我们实现了对所选择的接口的所有方法实现代理,但是代理逻辑却已经被写死了,自然不是很合适,这一篇我们便来解决这个问题,实现自定义代理逻辑的动态代理,实现之后我们的动态代理就已经很接近 JDK 自带的代理了。
- 要实现自定义代理逻辑,相信大家首先能想到的应该是定义一个接口 InvocationHandler ,我们所自定义的代理逻辑应该是实现了这个接口的逻辑类。
InvocationHandler 代码:package dynamicProxy; import java.lang.reflect.Method; public interface InvocationHandler { void invoke(Object o ,Method method) ; }
- 定义一种代理逻辑,把目标对象跟方法传进来。这里还是采用之前的代理逻辑即时间代理。
TimeHandler 代码:
这里的 target 为被代理对象,package dynamicProxy; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TimeHandler implements InvocationHandler { public TimeHandler(Object target) { this.target = target; } private Object target ; @Override public void invoke(Object o, Method method) { long startTime = System.currentTimeMillis() ; try { method.invoke(target, new Object[]{}) ; } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } long endTime = System.currentTimeMillis() ; System.out.println("time : " + (endTime - startTime)) ; } }
method.invoke(target, new Object[]{}) ;
中的 Object 数组是执行该方法的参数,这里为了简便操作先定义一个空数组。 - 接下来我们理所应当想到的就是修改生成代理类的工具,把代理逻辑也传进去。这里需要修改的地方有几处:
- 修改生成代理类的类,添加 newInstance 方法的参数 InvocationHandler:
public static Object newInstance(Class inface,InvocationHandler h)
- 修改代理类的生成代码 str,构造方法不再是所给定的代理类,而是 InvocationHandler
"public class TankTimeProxy implements "+ inface.getName() + "{\n" + " public TankTimeProxy(InvocationHandler h) {\n" + " this.handler = h;\n" + " }\n" + "\n" + " private InvocationHandler handler ;\n" + "\n" +
- 方法字符串中,原本是执行方法的 invoke 方法(
md.invoke(this, new Object[]{}) ;
),现在改为执行 handler 的 invoke 方法
" handler.invoke(this, md) ; \n" +
- 修改构造器参数:
Constructor constructor = c.getConstructor(InvocationHandler.class) ; Object m = constructor.newInstance(handler);
实际上到了这里,我们要实现的动态代理就已经完成了,可以完成对任意接口的所有方法实现我们自定义的代理逻辑。
这里再给出 Client 代码 :
Tank tank = new Tank() ;
Moveable tankTimeProxy = (Moveable)Proxy.newInstance(Moveable.class, new TimeHandler(tank)) ;
tankTimeProxy.move();
代码结果:

最后有几点需要说明:
- 为什么代理类的构造方法要改为 InvocationHandler?
我们已经知道,要实现代理肯定要有被代理对象,而我们在定义代理逻辑类的时候,已经把被代理对象作为构造方法的参数传进来了,所以代理类的构造方法定义为 InvocationHandler ,既包括了代理逻辑,也包括了被代理对象。 - 代理字符串中的 handler.invoke(this, md) 其中的 this 怎么理解?
this 关键字相信大家都有所了解,就是当前对象。那么在代理类字符串中,this 自然代表了代理对象。而我们代理逻辑中,这个对象暂时没有用到,但不代表以后我们不会用到。在 JDK 中,这个代理类的名字叫 $Proxy1 有兴趣的可以去看看。
网友评论