暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

「DUBBO系列」JDK动态代理机制

JAVA前线 2020-05-24
931

IT徐胖子原创本文未授权请勿转载


1 文章概述

Dubbo源码里有很多动态代理使用场景,例如源码里JdkProxyFactory正是使用了JDK动态代理。

    package org.apache.dubbo.rpc.proxy.jdk;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;


    public class JdkProxyFactory extends AbstractProxyFactory {


    @Override
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
    return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
    }


    @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
    return new AbstractProxyInvoker<T>(proxy, type, url) {
    @Override
    protected Object doInvoke(T proxy, String methodName,
    Class<?>[] parameterTypes,
    Object[] arguments) throws Throwable {
    Method method = proxy.getClass().getMethod(methodName, parameterTypes);
    return method.invoke(proxy, arguments);
    }
    };
    }
    }

    本文我们介绍JDK动态代理实现原理,后续文章再进行Dubbo源码分析。下面我们通过一个实例分析JDK动态代理实现原理。


    2 代码实例

    2.1 业务接口

      public interface StudentJDKService {
      public void addStudent();
      public void updateStudent();
      }


      public class StudentJDKServiceImpl implements StudentJDKService {
      @Override
      public void addStudent() {
      System.out.println("add student");
      }


      @Override
      public void updateStudent() {
      System.out.println("update student");
      }
      }


      2.2 InvocationHander

        import java.lang.reflect.InvocationHandler;
        import java.lang.reflect.Method;
        public class TransactionHandler implements InvocationHandler {


        // 被代理对象
        private Object target;


        // 构造函数
        public TransactionHandler(Object target) {
        this.target = target;
        }


        // 代理逻辑
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("transaction begin");
        Object result = method.invoke(target, args);
        System.out.println("transaction end");
        return result;
        }
        }


        2.3 测试用例

          public class TestStudentService {
          public static void main(String[] args) throws Exception {
          StudentJDKService target = new StudentJDKServiceImpl();
          TransactionHandler handler = new TransactionHandler(target);
          ClassLoader loader = target.getClass().getClassLoader();
          Class<?>[] interfaces = target.getClass().getInterfaces();
          StudentJDKService proxy = (StudentJDKService) Proxy.newProxyInstance(loader, interfaces, handler);
          System.out.println(proxy.getClass().getName());
          proxy.addStudent();
          }
          }


          // 输出结果
          // com.sun.proxy.$Proxy0
          // transaction begin
          // add student
          // transaction end


          3 源码分析

          3.1 分析入口

            StudentJDKService proxy = (StudentJDKService) Proxy.newProxyInstance(loader, interfaces, handler);


            3.2 Proxy

              public class Proxy implements java.io.Serializable {
              private static final Class<?>[] constructorParams = { InvocationHandler.class };
              protected InvocationHandler h;


              @CallerSensitive
              public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {


              // InvocationHandler不能为空
              Objects.requireNonNull(h);
              final Class<?>[] intfs = interfaces.clone();
              final SecurityManager sm = System.getSecurityManager();
              if (sm != null) {
              checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
              }
              // 获取指定代理类
              Class<?> cl = getProxyClass0(loader, intfs);


              try {
              // 权限校验
              if (sm != null) {
              checkNewProxyPermission(Reflection.getCallerClass(), cl);
              }
              // 获取代理类的构造器
              final Constructor<?> cons = cl.getConstructor(constructorParams);
              final InvocationHandler ih = h;
              if (!Modifier.isPublic(cl.getModifiers())) {
              AccessController.doPrivileged(new PrivilegedAction<Void>() {
              public Void run() {
              cons.setAccessible(true);
              return null;
              }
              });
              }
              // 通过代理类构造器实例化为代理对象
              return cons.newInstance(new Object[] {h});
              }
              }
              }


              3.3 getProxyClass0

                public class Proxy implements java.io.Serializable {


                // 代理类缓存
                // 如果缓存里不存则通过ProxyClassFactory生成代理类
                private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());


                private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
                if (interfaces.length > 65535) {
                throw new IllegalArgumentException("interface limit exceeded");
                }
                return proxyClassCache.get(loader, interfaces);
                }
                }


                3.4 ProxyClassFactory

                  private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
                  // 类名前缀
                  private static final String proxyClassNamePrefix = "$Proxy";
                  // 代理类序号
                  private static final AtomicLong nextUniqueNumber = new AtomicLong();


                  @Override
                  public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
                  Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);


                  // 遍历接口数组
                  for (Class<?> intf : interfaces) {
                  Class<?> interfaceClass = null;
                  try {
                  interfaceClass = Class.forName(intf.getName(), false, loader);
                  } catch (ClassNotFoundException e) {
                  }
                  if (interfaceClass != intf) {
                  throw new IllegalArgumentException(intf + " is not visible from class loader");
                  }
                  // 校验是否是接口
                  if(!interfaceClass.isInterface()) {
                  throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");
                  }
                  // 接口去重
                  if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                  throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());
                  }
                  }
                  // 代理类所在的包路径
                  String proxyPkg = null;
                  // 代理类的访问修饰符
                  int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
                  for (Class<?> intf : interfaces) {
                  int flags = intf.getModifiers();
                  if (!Modifier.isPublic(flags)) {
                  accessFlags = Modifier.FINAL;
                  String name = intf.getName();
                  int n = name.lastIndexOf('.');
                  String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                  if (proxyPkg == null) {
                  proxyPkg = pkg;
                  } else if (!pkg.equals(proxyPkg)) {
                  throw new IllegalArgumentException("non-public interfaces from different packages");
                  }
                  }
                  }
                  if (proxyPkg == null) {
                  proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
                  }
                  // 生成代理类名
                  long num = nextUniqueNumber.getAndIncrement();
                  String proxyName = proxyPkg + proxyClassNamePrefix + num;


                  // 核心方法生成代理类字节码
                  byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
                  try {
                  // 通过本地方法defineClass0生成代理
                  return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
                  } catch (ClassFormatError e) {
                  throw new IllegalArgumentException(e.toString());
                  }
                  }
                  }


                  4 代理类字节码分析

                  通过分析源码我们知道ProxyGenerator生成了代理类字节码,这是动态代理的核心。下面我们直接调用这个方法看看生成字节码的具体内容。

                    public class TestStudentService {


                    public static void main(String[] args) throws Exception {
                    createProxyClassFile();
                    }


                    public static void createProxyClassFile() {
                    String name = "Student$Proxy";
                    byte[] data = ProxyGenerator.generateProxyClass(name, new Class[] { StudentJDKService.class });
                    FileOutputStream out = null;
                    try {
                    // 字节码文件路径
                    String fileName = "c:/test/" + name + ".class";
                    File file = new File(fileName);
                    out = new FileOutputStream(file);
                    out.write(data);
                    } catch (Exception e) {
                    System.out.println(e.getMessage());
                    } finally {
                    if (null != out) {
                    try {
                    out.close();
                    } catch (IOException e) {
                    e.printStackTrace();
                    }
                    }
                    }
                    System.out.println();
                    }
                    }

                    找到代理类文件通过反编译工具打开得到如下代码,通过代码我们就可以看到动态代理实现原理。

                      import com.itxpz.dubbo.spi.proxy.jdk.StudentJDKService;
                      import java.lang.reflect.InvocationHandler;
                      import java.lang.reflect.Method;
                      import java.lang.reflect.Proxy;
                      import java.lang.reflect.UndeclaredThrowableException;


                      public final class Student$Proxy extends Proxy implements StudentJDKService {
                      private static Method m1;
                      private static Method m4;
                      private static Method m3;
                      private static Method m2;
                      private static Method m0;


                      public Student$Proxy(InvocationHandler paramInvocationHandler) {
                      super(paramInvocationHandler);
                      }


                      public final boolean equals(Object paramObject) {
                      try {
                      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
                      } catch (Error | RuntimeException error) {
                      throw null;
                      } catch (Throwable throwable) {
                      throw new UndeclaredThrowableException(throwable);
                      }
                      }


                      public final void updateStudent() {
                      try {
                                  // invocationHandler.invoke
                      this.h.invoke(this, m4, null);
                      return;
                      } catch (Error | RuntimeException error) {
                      throw null;
                      } catch (Throwable throwable) {
                      throw new UndeclaredThrowableException(throwable);
                      }
                      }


                      public final void addStudent() {
                      try {
                                  // invocationHandler.invoke
                      this.h.invoke(this, m3, null);
                      return;
                      } catch (Error | RuntimeException error) {
                      throw null;
                      } catch (Throwable throwable) {
                      throw new UndeclaredThrowableException(throwable);
                      }
                      }


                      public final String toString() {
                      try {
                      return (String)this.h.invoke(this, m2, null);
                      } catch (Error | RuntimeException error) {
                      throw null;
                      } catch (Throwable throwable) {
                      throw new UndeclaredThrowableException(throwable);
                      }
                      }


                      public final int hashCode() {
                      try {
                      return ((Integer)this.h.invoke(this, m0, null)).intValue();
                      } catch (Error | RuntimeException error) {
                      throw null;
                      } catch (Throwable throwable) {
                      throw new UndeclaredThrowableException(throwable);
                      }
                      }


                      static {
                      try {
                      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
                      m4 = Class.forName("com.itxpz.dubbo.proxy.jdk.StudentJDKService").getMethod("updateStudent", new Class[0]);
                      m3 = Class.forName("com.itxpz.dubbo.proxy.jdk.StudentJDKService").getMethod("addStudent", new Class[0]);
                      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
                      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
                      return;
                      } catch (NoSuchMethodException noSuchMethodException) {
                      throw new NoSuchMethodError(noSuchMethodException.getMessage());
                      } catch (ClassNotFoundException classNotFoundException) {
                      throw new NoClassDefFoundError(classNotFoundException.getMessage());
                      }
                      }
                      }


                      5 文章总结

                      本文我们介绍了JDK动态代理实现原理,后续文章再进行Dubbo源码分析,到时候会看到大量使用动态代理的场景。


                      长按二维码关注更多精彩文章

                      文章转载自JAVA前线,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                      评论