资讯专栏INFORMATION COLUMN

Java基础 :java的代理模式

MartinHan / 603人阅读

摘要:如果那个对象在的某个远端服务器上直接操作这个对象因为网络速度原因可能比较慢那我们可以先用来代替那个对象。这种在运行期直接通过虚拟机加入二进制字节码的方法是实现动态代理的手段

代理的目的到底是什么呢?字面意思上就可以解释:代理就是“代人理事”,也就是说当实现某个操作的时候发现根本不能使用相关的对象或者使用这个对象的效果不好的时候就建立一个“代它理事”的代理对象,让代理对象去完成任务,因为我们关注的是完成任务本身,至于是谁完成了这个任务是不重要的。在这种逻辑下,只要建立的代理对象能够实现像原来那个对象一样的方法就行,更进一步说,我们新建的这个代理对象有足够大的自由度,不仅可以完成原来那个对象的功能,还能完成其他我们附加上的功能。
举两个例子:

如果那个对象是一个是很大的图片,需要花费很长时间才能显示出来,那么当这个图片包含在文档中时,使用编辑器或浏览器打开这个文档,打开文档必须很迅速,不能等待大图片处理完成,这时需要做个图片Proxy来代替真正的图片。

如果那个对象在Internet的某个远端服务器上,直接操作这个对象因为网络速度原因可能比较慢,那我们可以先用Proxy来代替那个对象。

我们来说说静态代理和动态代理:
静态代理:我们的代理对象是手动创建的,代理对象内部是有一个被代理对象对应的类的对象的,所以如果想要执行某些被代理对象的方法时就可以使用这个新建的代理对象的同名方法去执行,这个时候执行的逻辑里面其实就可以用这个内部对象的同名方法。

interface Subject{
        public void operate();
}

class SubjectImpl implements Subject{
        @Override
        public void operate() {
              System. out.println( "real operate");
       }
}

class SubjProxy implements Subject{
       SubjectImpl subjectImpl = new SubjectImpl();
        @Override
        public void operate() {
              System. out.println( "proxy starts");
               subjectImpl.operate();
       }
}

public class TestClass {
        public static void main(String[] args) {
              SubjProxy proxy = new SubjProxy();
              proxy.operate();
       }
}

通过上面的例子我们可以看出来新建的代理对象拥有和原对象相同的接口,所以可以像操作原对象一样地去操作代理对象,代理对象的方法还可以做出拓展,做到原对象做不了的事情。

动态代理:通过查看静态类型的例子,我们有了新的问题:我们其实并想要一个准确的内部对象来完成实际的动作,我们想要的就是原对象的类结构,然后通过重写这个类结构中的相关方法去直接完成任务,在java中,我们完全可以通过反射去解决这个问题,完全不需要再去在代理对象内部搞一个原对象类型的对象出来。

interface Subject{
        public void operate();
}

class SubjectImpl implements Subject{
        @Override
        public void operate() {
              System. out.println( "real operate");
       }
}

public class TestClass {
        public static void main(String[] args) {
              Subject subject = (Subject)Proxy.newProxyInstance(SubjectImpl. class.getClassLoader(), SubjectImpl.class.getInterfaces(), new InvocationHandler() {
                      @Override
                      public Object invoke(Object proxy, Method method, Object[] args)
                                   throws Throwable {
                                  System. out.println( "Proxy operate");
                            return null;
                     }
              });
              subject.operate();
       }
}

动态代理的方式其实是反射的一种体现,为了让最后的代理对象能够真的去执行被代理的对象才能完成的任务,代理对象必须要得到被代理对象的类的结构,这样就能获取到被代理对象的方法,截获这个方法后可以使得方法重定向到代理对象的invoke方法上执行被重写的代理方法。所以新建代理对象实例的时候要将被代理类的类加载器、类实现的接口和重写被代理类方法的处理器对象作为参数构造代理对象,类加载器用以在后面使用这个代理对象的时候能够由被代理类的类加载器所加载,类的实现接口用以使得这个代理对象可以对外宣称自己实现了这些接口,重写方法的处理器用于真正地重写那些需要代理的方法,这样一来我们可以像使用被代理对象一样去使用代理对象,实现了代理对象能够真的做到“代人理事”。

interface Subject{
        public void operate();
        public int func();
}

class SubjectImpl implements Subject{
        @Override
        public void operate() {
              System. out.println( "real operate");
       }

        @Override
        public int func() {
              System. out.println( "func");
               return 2;
       }
       
}

public class TestClass {
        public static void main(String[] args) {
              Subject subject = (Subject)Proxy.newProxyInstance(SubjectImpl. class.getClassLoader(), SubjectImpl.class.getInterfaces(), new InvocationHandler() {
                      @Override
                      public Object invoke(Object proxy, Method method, Object[] args)
                                   throws Throwable {
                            if(method.getName().equals( "operate"))
                                  System. out.println( "Proxy operate");
                            else {
                                  System. out.println( "func");
                                   return new Integer(1);
                           }
                            return null;
                     }
              });
              subject.operate();
              System. out.println(subject.func());
       }
}

代理模式在虚拟机中的实现其实也不复杂,在运行期在字节码的基础上新创建一个临时代理类,临时代理类的各方法其实就是被代理类的同名方法的反射,执行这些方法的时候就会执行被代理的类中的反射出的同名方法。这种在运行期直接通过虚拟机加入二进制字节码的方法是实现动态代理的手段:

public final class $Proxy0 extends java.lang.reflect.Proxy implements Subject{
    public $Proxy0(java.lang.reflect.InvocationHandler)       throws ;
    public final int func()       throws ;
    public final boolean equals(java.lang.Object)       throws ;
    public final int hashCode()       throws ;
    public final void operate()       throws ;
    public final java.lang.String toString()       throws ;
    static {}       throws ;
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64692.html

相关文章

  • 给女朋友讲解什么是代理模式

    摘要:受知乎文章和设计模式之禅的启发,我也来搞一篇脑洞小开的文章由标题可知,这篇文章是写给我女朋友看的。于是这就让经纪人对粉丝说只有万,我才会写代码。 前言 只有光头才能变强 回顾前面: ThreadLocal就是这么简单 多线程三分钟就可以入个门了! 多线程基础必要知识点!看了学习多线程事半功倍 Java锁机制了解一下 AQS简简单单过一遍 Lock锁子类了解一下 线程池你真不来了解一下...

    stormgens 评论0 收藏0
  • Java三种代理模式

    Java的三种代理模式 参考:http://www.cnblogs.com/cenyu/...Java核心技术原书第九版6.5节 为什么使用代理   我们在写一个功能函数时,经常需要在其中写入与功能不是直接相关但很有必要的代 码,如日志记录,信息发送,安全和事务支持等,这些枝节性代码虽然是必要的,但它会带来以下麻烦: 枝节性代码游离在功能性代码之外,它不是函数的目的,这是对OO是一种破坏 枝节性...

    Rango 评论0 收藏0
  • Java 总结

    摘要:中的详解必修个多线程问题总结个多线程问题总结有哪些源代码看了后让你收获很多,代码思维和能力有较大的提升有哪些源代码看了后让你收获很多,代码思维和能力有较大的提升开源的运行原理从虚拟机工作流程看运行原理。 自己实现集合框架 (三): 单链表的实现 自己实现集合框架 (三): 单链表的实现 基于 POI 封装 ExcelUtil 精简的 Excel 导入导出 由于 poi 本身只是针对于 ...

    caspar 评论0 收藏0
  • Java设计模式代理模式

    摘要:设计模式之代理模式今天学到的动态代理实现,对代理这个概念很模糊,看了一篇文章发现这是一种设计模式,于是学习记录一下。简介代理模式是一种对象结构型的模式,主要为其他对象提供一种代理以控制对这个对象的访问。下面依次讲解着三种代理。 设计模式之代理模式 今天学到Spring的动态代理实现AOP,对代理这个概念很模糊,看了一篇文章发现这是一种设计模式,于是学习记录一下。 简介 代理模式是一种对...

    ZHAO_ 评论0 收藏0
  • Javag工程师成神之路(2019正式版)

    摘要:结构型模式适配器模式桥接模式装饰模式组合模式外观模式享元模式代理模式。行为型模式模版方法模式命令模式迭代器模式观察者模式中介者模式备忘录模式解释器模式模式状态模式策略模式职责链模式责任链模式访问者模式。 主要版本 更新时间 备注 v1.0 2015-08-01 首次发布 v1.1 2018-03-12 增加新技术知识、完善知识体系 v2.0 2019-02-19 结构...

    Olivia 评论0 收藏0

发表评论

0条评论

MartinHan

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<