zoukankan      html  css  js  c++  java
  • java中的动态代理

    我觉得要理解动态代理,首先要理解静态代理,因为动态代理是为了解决静态的问题才出现,详见上一篇静态代理的总结,直接看图

    可以看出来,代理的实现就是这三方类,所以为了解决静态代理的弊端,需要在运行的时候动态的生成代理类。

    而在java中jdk提供了proxy类创建动态类,jdk中是这样定义的

     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                              new Class<?>[] { Foo.class },
                                              handler);

    先说明一下三个参数,第一个参数是被代理类的类加载器,第二个参数是被代理类的实例,最重要的是第三个参数,是一个InvocationHandler对象,最终我们要调用的方法就是要传入这个handler对象,

    这个handle对象里面只有invoke方法

    invoke(Object proxy, 方法 method, Object[] args)

    处理代理实例上的方法调用并返回结果。 
    这是在jdk上的解释,说白了,我们要做的业务逻辑就是写在这里,这个invoke里面也有三个参数,其实我觉得proxy类里面对这三个参数解释的挺清楚的了,
    • 通过其代理接口之一的代理实例上的方法调用将被分派到实例调用处理程序的invoke方法,代理实例, java.lang.reflect.Method被调用方法的java.lang.reflect.Method对象以及包含参数的类型Object Object的数组。 调用处理程序适当地处理编码方法调用,并且返回的结果将作为方法在代理实例上调用的结果返回。

      第一个参数proxy是我们动态创建的代理对象,就是上面的第一句话,代理实例!第二参数就是目标方法的字节码对象,就是被代理方法的方法组成的数组,如果你不懂什么是字节码或者类加载器,你就直接当成方法数组就好了,最后一个参数代表是调用目标方法时参数。返回就是调用代理对象方法的返回返回就可以了

      /*
      * 接口
      * */
      public interface TargetInterface {
      
          public void method1();
          public String method2();
          public int method3(int x);
      }
      /*
      * 被代理类
      * */
      public class Target implements TargetInterface{
      
          @Override
          public void method1() {
              System.out.println("method1 running...");
          }
      
          @Override
          public String method2() {
              System.out.println("method2 running...");
              return "method2";
          }
      
          @Override
          public int method3(int x) {
              return x;
          }
      }
      /*
      * 测试动态代理
      * */
      public class ProxyTest {
      
          @Test
          public void test1(){
              //获得动态的代理对象----在运行时 在内存中动态的为Target创建一个虚拟的代理对象
              //objProxy是代理对象 根据参数确定到底是谁的代理对象
              TargetInterface objProxy = (TargetInterface) Proxy.newProxyInstance(
                      Target.class.getClassLoader(), //与目标对象相同的类加载器
                      new Class[]{TargetInterface.class}, 
                      new InvocationHandler() {
                          //invoke 代表的是执行代理对象的方法
                          @Override
                          //method:代表目标对象的方法字节码对象
                          //args:代表目标对象的响应的方法的参数
                          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                              System.out.println("目标方法前的逻辑");
                              //执行目标对象的方法
                              Object invoke = method.invoke(new Target(), args);
                              System.out.println("目标方法后的逻辑");
                              return invoke;
                          }
                      }
                  );
              
              objProxy.method1();
              String method2 = objProxy.method2();
              System.out.println(method2);
              
          }
          
      }

      这里面很多东西我已经注释了,比较难理解的可能是这一句

      Object invoke = method.invoke(new Target(), args);

      这句代码如果你了解反射的话,应该可以看出来,这其实就是做了一个反射,第一个参数就是被代理类的实例,args就是方法的参数,这句话其实就是调用被代理对象的方法。也就是说在这个invoke里面我们可以对对象进行增强,

      最后我再总结一下,动态代理底层应该使用了反射的原理,根据传进来的类的接口的字节码文件(即new Class<?>[] { Foo.class }参数),动态的创建一个代理类,当我们在调用这个代理类的方法的时候(即objProxy.method1();

      我们实际上调用了invoke方法,反射的使用了被代理类的方法。

  • 相关阅读:
    [Swift]LeetCode922.按奇偶排序数组 II | Sort Array By Parity II
    [Swift]LeetCode921.使括号有效的最少添加 | Minimum Add to Make Parentheses Valid
    [Swift实际操作]八、实用进阶-(5)通过间接代理进行对象间的消息传递
    [Swift]LeetCode927. 三等分 | Three Equal Parts
    [Swift]LeetCode928. 尽量减少恶意软件的传播 II | Minimize Malware Spread II
    我是大牛,我自豪
    程序员拓展人脉的重要性
    程序员拓展人脉的重要性
    2013年总结(3)-活动篇
    2013年总结(3)-活动篇
  • 原文地址:https://www.cnblogs.com/qunincey/p/9398369.html
Copyright © 2011-2022 走看看