代理

作者: 爱做梦的严重精神病患者 | 来源:发表于2018-12-07 23:45 被阅读0次

1.代理原理

 利用动态代理可以在运行时创建一个实现了一组给定接口的新类。假设有一个表示接口的Class对象,它的确切类型在编译时无法知道(Proxy.newInstance()方法ClassLoader参数为null的情况)。所以要想构造一个实现这些接口的类,需要使用newInstance()方法反射找出这个类的构造器。但是,不能实例化一个接口,需要在程序处于运行状态时定义一个新类
 代理机制可以满足上述需求,代理类可以在运行时创建全新的类,这样的代理类能够实现指定的接口

2.代理场景

代理这种设计模式是通过不直接访问被代理对象的方式,而访问代理对象的方法。这个就好比商户---->明星经纪人(代理)---->明星这种模式。我们可以不通过直接与明星对话的情况下,而通过明星经纪人(代理)与其产生间接对话
设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的代码,里面代码逻辑让人摸不着头脑,这时就很难去下手修改代码,那么这时我们就可以通过代理对类进行增强

3.代理实现

在java中规定,要想产生一个对象的代理对象,那么这个对象必须要有一个接口

public interface Person {
 
     String sing(String name);

     String dance(String name);
 }

public class LiuDeHua implements Person {
 
     public String sing(String name){
         System.out.println("刘德华唱"+name+"歌!!");
         return "歌唱完了,谢谢大家!";
     }
     
     public String dance(String name){
         System.out.println("刘德华跳"+name+"舞!!");
         return "舞跳完了,多谢各位观众!";
     }
 }

 要想创建一个代理对象,需要使用Proxy类的newProxyInstance方法。这个方法需要三个参数:
ClassLoader loader:指定一个动态加载代理类的类加载器(可为null)
Class<?>[] interfaces:指明被代理类实现的接口,之后我们通过拼接字节码生成的类才能知道调用哪些方法。
InvocationHandler h:这是一个方法委托类,我们通过代理调用被代理类的方法时,就可以将方法名和方法参数都委托给这个委托类。

public class LiuDeHuaProxy {
 
     //设计一个类变量记住代理类要代理的目标对象
     private Person ldh = new LiuDeHua();
     
     /**
     * 设计一个方法生成代理对象
     * @Method: getProxy
     * @Description: 这个方法返回刘德华的代理对象:Person person = LiuDeHuaProxy.getProxy();//得到一个代理对象
     * @return 某个对象的代理对象
     */ 
     public Person getProxy() {
         //使用Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)返回某个对象的代理对象
         return (Person) Proxy.newProxyInstance(LiuDeHuaProxy.class
                 .getClassLoader(), ldh.getClass().getInterfaces(),
                 new InvocationHandler() {
                     /**
                      * InvocationHandler接口只定义了一个invoke方法,因此对于这样的接口,我们不用单独去定义一个类来实现该接口,
                      * 而是直接使用一个匿名内部类来实现该接口,new InvocationHandler() {}就是针对InvocationHandler接口的匿名实现类
                      */
                     /**
                      * 在invoke方法编码指定返回的代理对象干的工作
                      * proxy : 把代理对象自己传递进来 
                      * method:把代理对象当前调用的方法传递进来 
                      * args:把方法参数传递进来
                      * 
                      * 当调用代理对象的person.sing("冰雨");或者 person.dance("江南style");方法时,
                      * 实际上执行的都是invoke方法里面的代码,
                      * 因此我们可以在invoke方法中使用method.getName()就可以知道当前调用的是代理对象的哪个方法
                      */
                     @Override
                     public Object invoke(Object proxy, Method method,
                             Object[] args) throws Throwable {
                         //如果调用的是代理对象的sing方法
                         if (method.getName().equals("sing")) {
                             System.out.println("我是他的经纪人,要找他唱歌得先给十万块钱!!");
                             //已经给钱了,经纪人自己不会唱歌,就只能找刘德华去唱歌!
                             return method.invoke(ldh, args); //代理对象调用真实目标对象的sing方法去处理用户请求
                         }
                         //如果调用的是代理对象的dance方法
                         if (method.getName().equals("dance")) {
                             System.out.println("我是他的经纪人,要找他跳舞得先给二十万块钱!!");
                             //已经给钱了,经纪人自己不会唱歌,就只能找刘德华去跳舞!
                             return method.invoke(ldh, args);//代理对象调用真实目标对象的dance方法去处理用户请求
                         }
 
                         return null;
                     }
                 });
     }
 }
public class ProxyTest {     
      public static void main(String[] args) {
          LiuDeHuaProxy proxy = new LiuDeHuaProxy();
          //获得代理对象
          Person p = proxy.getProxy();
         //调用代理对象的sing方法
         String retValue = p.sing("冰雨");
         System.out.println(retValue);
         //调用代理对象的dance方法
         String value = p.dance("江南style");
         System.out.println(value);
     }
 }

对于特定的类的加载器预设的一组接口来说,只能有一个代理类。也就是说,如果使用同一个类加载器接口数组调用两次newProInstance方法的话,那么只能得到同一个类得两个对象

 可以通过调用Proxy类中的isProxyClass方法检测一个特定的Class对象是否代表一个代理类。

4.动态代理和静态代理的区别

静态代理:

public class Proxy implements Person {
     private LiuDeHua mLDH;
      
     public Proxy(LiudeHua ldh){
      this.mLDH = ldh;
      }
     public String sing(String name){
         mLDH.sing(name);
     }
     
     public String dance(String name){
         mLDH.dance(name);
     }
 }

 根据加载被代理类时机不同,将代理分为静态代理动态代理。如果在代码编译时确定被代理的类是哪一个,那么就可以直接使用静态代理;如果不能确定,那么可以使用类的动态加载机制,在代码运行期间加载被代理的类这就是动态代理,比如RPC框架和Spring AOP机制。

 对于静态代理方式代理类需要实现和被代理类相同的接口;对于动态代理代理类不需要显示地实现被代理类所实现的接口

相关文章

  • 正向代理和反向代理(通俗易懂)

    正向代理:代理端代理的是客户端。反向代理:代理端代理的是服务端。 常用案例 正向代理:如VPN代理客户端 反向代理...

  • 编程常用的设计模式

    动态代理和静态代理 静态代理 动态代理 静态代理与动态代理的区别 JDK中的动态代理和CGLIB 实现动态代理的方...

  • JAVA动态代理的实现方式

    1. 静态代理VS动态代理 代理类可以增强被代理对象的方法。可分为静态代理和动态代理。 1.1 静态代理 静态代理...

  • 面试系列~动态代理实现与原理

    动态代理有JDK动态代理, CGLIB动态代理, SpringAOP动态代理 一,JDK动态代理  jdk动态代理...

  • Nginx作为代理服务

    一、代理服务代理-代为办理(代理理财、代理收货等等) 1.1正向代理 1.2反向代理 1.3代理区别 1.4配置语...

  • Spring之代理模式

    九、代理模式 目录:静态代理、动态代理AOP的底层机制就是动态代理。代理模式分为静态代理和动态代理。接触aop之前...

  • Spring的AOP原理分析

    一 动态代理 动态代理分为JDK动态代理和CGLIB动态代理 jdk动态代理 被代理类(目标类)和代理类必须实现同...

  • 静态代理、动态代理

    代理分为静态代理和动态代理 按照代理创建的时期,可以分为静态代理和动态代理: (1) 静态代理:由程序员或者...

  • Java 代理的实现原理

    一、怎样使用代理 二、代理实现的原理 一、代理分为静态代理和动态代理 静态代理:代理对象获得目标对象的引用 动态代...

  • spring aop

    JDK动态代理和CGLib代理 JDK的代理代理类 被代理接口 被代理实现类 启动类: jdk的动态代理是针对接口...

网友评论

      本文标题:代理

      本文链接:https://www.haomeiwen.com/subject/azqrcqtx.html