代理模式(三) ---- 实现自定义代理逻辑的动态代理

上一篇我们实现了对所选择的接口的所有方法实现代理,但是代理逻辑却已经被写死了,自然不是很合适,这一篇我们便来解决这个问题,实现自定义代理逻辑的动态代理,实现之后我们的动态代理就已经很接近 JDK 自带的代理了。


  1. 要实现自定义代理逻辑,相信大家首先能想到的应该是定义一个接口 InvocationHandler ,我们所自定义的代理逻辑应该是实现了这个接口的逻辑类。
    InvocationHandler 代码:
    package dynamicProxy;
    
    import java.lang.reflect.Method;
    
    public interface InvocationHandler {
        void invoke(Object o ,Method method) ;
    }
    
  2. 定义一种代理逻辑,把目标对象跟方法传进来。这里还是采用之前的代理逻辑即时间代理。
    TimeHandler 代码:
    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)) ;
    
        }
    }
    
    
    这里的 target 为被代理对象,method.invoke(target, new Object[]{}) ; 中的 Object 数组是执行该方法的参数,这里为了简便操作先定义一个空数组。
  3. 接下来我们理所应当想到的就是修改生成代理类的工具,把代理逻辑也传进去。这里需要修改的地方有几处:
    • 修改生成代理类的类,添加 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();

代码结果:

结果

最后有几点需要说明:

  1. 为什么代理类的构造方法要改为 InvocationHandler?
    我们已经知道,要实现代理肯定要有被代理对象,而我们在定义代理逻辑类的时候,已经把被代理对象作为构造方法的参数传进来了,所以代理类的构造方法定义为 InvocationHandler ,既包括了代理逻辑,也包括了被代理对象。
  2. 代理字符串中的 handler.invoke(this, md) 其中的 this 怎么理解?
    this 关键字相信大家都有所了解,就是当前对象。那么在代理类字符串中,this 自然代表了代理对象。而我们代理逻辑中,这个对象暂时没有用到,但不代表以后我们不会用到。在 JDK 中,这个代理类的名字叫 $Proxy1 有兴趣的可以去看看。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,845评论 18 139
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,757评论 0 9
  • 本文属于系列文章《设计模式》,附上文集链接 本文集代理模式请看此处 前言 上一篇写的那个代理模式,是属于静态代理。...
    l_sivan阅读 345评论 0 1
  • 事例 小张是一个普普通通的码农,每天勤勤恳恳地码代码。某天中午小张刚要去吃饭,一个电话打到了他的手机上。“是XX公...
    余平的余_余平的平阅读 503评论 0 0
  • 小刘学习成绩一直都不错,在班里的名次平时也算中上游,大家都以为他能考上自己的目标学校,但现实就是这么残酷,在高考时...
    eryerwertwe阅读 222评论 0 0