zoukankan      html  css  js  c++  java
  • 代理模式

    代理类的诞生背景?

    在实际开发中会经常会遇见这样的一种情况:

      原有类具有一些功能,但其具有的功能又不能满足我们的需求。在此情况下,我们可以对 原有类 进行增强处理。但是必须遵循《设计原则》中“开闭原则”的相关规定 —— “对扩展开放,修改关闭”。

    那么如何在不改变原有类的前提下,对原有类功能进行增强呢?

      解决思路:创建一个代理对象,使用代理对象来充当"中介"的角色。

           使用代理对象,是为了在不修改目标方法功能的基础上,在代理类中增强自己的功能代码 来实现增强目标类主业务逻辑。

      重点注意:最后代码执行时,真正使用的是代理类。

    代理类完成的功能:
      1. 调用目标方法,执行目标方法的功能
      2. 功能增强,在目标方法调用时,增加功能。


    代理模式

    Proxy Pattern

    什么是代理模式?

      代理模式是指,为其他对象提供一种代理 ,以控制对这个对象的访问。

      客户类真正的想要访问的对象是目标对象,但客户类实际可以访问的对象是代理对象。

      在实际开发中,当遇见 一个对象不适合 或者 不能直接引用另一个对象的情况时,可以创建代理类。通过使用代理对象来实现客户类对目标对象的访问。  

      由此可见,代理对象可以在客户端和目标对象之间起到中介的作用,同时也起到了保护了目标对象的作用。     

      注意事项:代理类需要实现和目标类一致的接口。

    三个角色:客户端类  、 代理类、 目标类                                  

                                                                           ---

    使用代理模式的作用?

    (1)职责清晰;
      真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。

    (2)功能增强。增强目标类主业务逻辑;

      在你原有的功能上,增加了额外的功能。 新增加的功能,叫做功能增强。

    (3)控制访问;
        代理类不让你访问目标,例如商家不让用户访问厂家。

      在开发中也会有这样的情况, 你有A类, 本来是调用C类的方法, 完成某个功能。 但是C不让A调用。 那么只能在A和C之间 创建一个B作为C的代理让A访问。  
        B将访问C的结果,交给A。从而达到A间接访问到C的效果
          
      

    静态代理和动态代理的区别?

      静态代理是由程序员手动创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

      动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。

      要从直观的代码中  鉴别 静态代理 和 动态代理,观察代码即可。 通常情况下,只要程序中 需要自己定义代理类,这就是静态代理。程序无需定义代理类, 但是 代理对象是通过  工厂 或 工具 在运行时 生成的,此时的代理 为 动态代理。

    静态代理:  指的是程序还没有运行,两个类之间就已经建立了代理关系。

    原理:

    要求:1) 代理类是自己手工实现的,自己创建一个java类,表示代理类。

          2)同时你所要代理的目标类是确定的。

    特点:1)实现简单 

          2)容易理解。

    缺点:1)当目标类增加了, 代理类可能也需要成倍的增加。 代理类数量过多。

          2) 当你的接口中功能增加了, 或者修改了,会影响众多的实现类,厂家类,代理都需要修改。影响比较多。

    动态代理:  指的是程序在运行过程中,才生成一个代理对象。而该代理对象 作用就是 为目标对象 作 代理。     

      当在静态代理中目标类很多时候,可以使用动态代理,来避免使用静态代理的缺点。
        动态代理中目标类即使很多, 1)代理类数量可以很少。 2)当你修改了接口中的方法时,并不会影响代理类。
        动态代理: 在程序执行过程中,使用jdk的反射机制,创建代理类对象, 并动态的指定要代理目标类。
        换句话说: 动态代理是一种创建java对象的能力,让你不用创建TaoBao类,就能创建代理类对象。

     


    回顾在java中,常规的创建对象方式步骤:    

      1)先创建类文件, java文件编译为class;    

      2)再使用构造方法,创建类的对象;

    动态代理的分类?

    动态代理类型的选择原则:

      目标类有实现接口     ——   使用JDK动态代理 或 CGLIB动态代理 
      目标类没有实现接口  ——   只能使用CGLIB动态代理。

    1)JDK的Proxy动态代理

      原理:(与静态代理的相同)

      要求: 目标类 必须要实现接口。

    JDK的反射机制,提供了在程序运行时创造对象的能力。于是可以使用java反射包中的类和接口来实现动态代理的功能:

    调用反射包中的相关方法,在程序执行时,创建代理类的对象。而无需再由程序员来手动创建代理类的java文件。

    需要使用到 java.lang.reflect 反射包中的三个类/接口:

    InvocationHandler接口

    jdk动态代理:
           1. 反射, Method类,表示方法。类中的方法。 通过Method可以执行某个方法。

    1)InvocationHandler 接口(调用处理器):就一个方法invoke()
                   invoke():表示代理对象要执行的功能代码。你的代理类要完成的功能就写在   invoke()方法中。
                                              
    方法原型:(3个参数)
    InvocationHandler “调用处理器”接口:表示你的代理要干什么。

      public Object invoke(Object proxy, Method method, Object[] args)
        Object proxy ——jdk创建的代理对象,无需赋值。
        Method method——代表目标类中的方法,jdk提供method对象的。无需赋值。
        Object[] args——目标类中方法的参数, jdk提供的。无需赋值。

           
    如何使用?
     1.创建类实现接口InvocationHandler。
     2.重写invoke()方法, 把原来静态代理中代理类要完成的功能,写在这。

    Method类 ————  表示方法的, 确切的说就是目标类中的方法。
                作用:通过Method可以执行某个目标类的方法,Method.invoke();
                        method.invoke(目标对象,方法的参数)
                          Object ret = method.invoke(service2, "李四");

                说明: method.invoke()就是用来执行目标方法的,等同于静态代理中的
                         //向厂家发送订单,告诉厂家,我买了u盘,厂家发货
                      float price = factory.sell(amount); //厂家的价格。

    Proxy类   ————  创建代理对象。

      常规的创建对象方式: new 类的构造方法()。缺点是代码固定,不灵活,代码扩展性差。

      反射方式创建对象:使用Proxy类的方法,代替new的使用,来创建对象。
                

    方法: 静态方法 newProxyInstance()
                作用是: 创建代理对象, 等同于静态代理中的TaoBao taoBao = new TaoBao()

     参数:
                 1. ClassLoader loader 类加载器,负责向内存中加载对象的。 使用反射获取对象的ClassLoader
                      类a , a.getCalss().getClassLoader(),  目标对象的类加载器
              2. Class<?>[] interfaces: 接口, 目标对象实现的接口,也是反射获取的。
              3. InvocationHandler h : 我们自己写的,代理类要完成的功能。
    
                返回值:就是代理对象
    
                public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h) 

     


    2)CGLIB动态代理

    原理: