• java jdk动态代理流程


    基于jdk1.8
    jdk动态代理,是相对于静态代理来说,是jvm Runtime 运行时生成的代理类
    静态代理指的是硬编码(代码里面写死的),所以称为动态代理。

    what 怎么使用

    MyProxyTest

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Proxy;
    
    public class MyProxyTest {
      public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        // 用于输出生成的代理类的class类到文件里面,可以看一下
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        // 生成代理类
        Class proxyClazz = Proxy.getProxyClass(IHello.class.getClassLoader(), IHello.class);
        // 获取代理类的构造函数
        Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class);
        // 生成对象
        IHello iHello = (IHello) constructor.newInstance(new MyInvocationHandler(new HelloImpl()));
        // 调用方法
        iHello.sayHello();
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    IHello 接口

    public interface IHello {
    
      void  sayHello();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    实现类

    public class HelloImpl implements  IHello{
      @Override
      public void sayHello() {
        System.out.println("hello world");
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    MyInvocationHandler

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class MyInvocationHandler implements InvocationHandler {
      private Object target;
    
      public MyInvocationHandler(Object target) {
        this.target = target;
      }
    
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before invoke ------------> ");
        Object rs =  method.invoke(target, args);
        System.out.println("after invode -------------> ");
        return rs;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Why

    为什么只能对接口进行代理,无法对类进行代理
    1, 使用场景,动态代理机制只支持接口的代理, 这个可能是因为当时和Spring AOP技术
    进行配合,因为spring的IOC等约定都是面向接口变成,接口和实现分离的形式。
    2, 实现机制,动态代理最后生成的代理类,会继续Proxy类,复用一些接口吧,java面向对象设计原则目前地是为了复用
    ,当然这里使用组合的方式肯定也是可以的,使用继承我个人认为可能是想标识,这就是个代理类,属于代理体系。
    因为继承是父子继承,是有相应的关系的。如果这里继承的业务类,但是其实具体的代码并不是父类的向下扩展
    代理一般都是针对同类进行横向增强的,可能和面向对象的思想也有点冲突。

    how 具体怎么实现的

    具体的流程看代码就是,细节自己看代码吧,就不贴了

    • 新增 hashCode, equal, toString 三个方法 然后遍历所有的代理接口,
    • 把所有的方法都新增到代理类中,如果有签名一样,返回值一样的方法,则进行方法异常的合并,保证运行正常,但是最后只会生成一个代理方法。
    • 包路径,正常是com.sun.proxy, 如果存在非public的接口,则生成的代理类package会和其一样,但是不能存在两个非public的,且包路径不一样的接口,这样没办法增强了,会报错。
    • 生成的代理类的名字,就是$Proxy+当前生成代理类 个数,比如 第一个 $Proxy1, 第二个 $Proxy2
    • 代理类通过invoker方法调用具体的代理实现,会带上方法名称,可以看下面生成的代理类。

    生成的代理类

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package com.sun.proxy;
    
    import com.xiaomi.mifi.instalment.api.utils.IHello;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class $Proxy0 extends Proxy implements IHello {
      private static Method m1;
      private static Method m3;
      private static Method m2;
      private static Method m0;
    
      public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
      }
    
      public final boolean equals(Object var1) throws  {
        try {
          return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
          throw var3;
        } catch (Throwable var4) {
          throw new UndeclaredThrowableException(var4);
        }
      }
    
      public final void sayHello() throws  {
        try {
          super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
          throw var2;
        } catch (Throwable var3) {
          throw new UndeclaredThrowableException(var3);
        }
      }
    
      public final String toString() throws  {
        try {
          return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
          throw var2;
        } catch (Throwable var3) {
          throw new UndeclaredThrowableException(var3);
        }
      }
    
      public final int hashCode() throws  {
        try {
          return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
          throw var2;
        } catch (Throwable var3) {
          throw new UndeclaredThrowableException(var3);
        }
      }
    
      static {
        try {
          m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
          m3 = Class.forName("com.xiaomi.mifi.instalment.api.utils.IHello").getMethod("sayHello");
          m2 = Class.forName("java.lang.Object").getMethod("toString");
          m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
          throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
          throw new NoClassDefFoundError(var3.getMessage());
        }
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
  • 相关阅读:
    振弦式渗压计与振弦采集仪组成大坝水库安全监测的案例
    软件开发模型
    IDEA插件开发(25)--Color Scheme Management
    09 【Attributes继承 provide与inject】
    深入理解JVM(一) JVM是做什么的
    Nginx请求强制缓存设置
    day60
    Netty网络框架学习笔记-19(实现一个简单RPC-1)
    matplotlib ax bar color 设置ax bar的颜色、 透明度、label legend
    网路了解篇-1
  • 原文地址:https://blog.csdn.net/li740207611/article/details/125624924