欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

java 1.8 动态代理源码深度分析

程序员文章站 2023-12-19 17:34:04
jdk8动态代理源码分析 动态代理的基本使用就不详细介绍了: 例子: class proxyed implements pro{ @override...

jdk8动态代理源码分析

动态代理的基本使用就不详细介绍了:

例子:

class proxyed implements pro{
 @override
 public void text() {
  system.err.println("本方法");
 }
}

interface pro {
 void text();
}

public class javaproxy implements invocationhandler {
  private object source;
  public javaproxy(object source) {
   super();
   this.source = source;
  }
  public object invoke(object proxy, method method, object[] args) throws throwable {
   system.out.println("before");
   object invoke = method.invoke(source, args);
   system.out.println("after");
   return invoke;
  }
  public object getproxy(){
   return proxy.newproxyinstance(getclass().getclassloader(), source.getclass().getinterfaces(), this);
  }
  public static void main(string[] args) throws illegalaccessexception, invocationtargetexception, instantiationexception, nosuchmethodexception {
   //第一种,自己写
   //1.设置savegeneratedfiles值为true则生成 class字节码文件方便分析
   system.getproperties().put("sun.misc.proxygenerator.savegeneratedfiles", "true");
   //2.获取动态代理类
   class proxyclazz = proxy.getproxyclass(pro.class.getclassloader(),pro.class);
   //3.获得代理类的构造函数,并传入参数类型invocationhandler.class
   constructor constructor = proxyclazz.getconstructor(invocationhandler.class);
   //4.通过构造函数来创建动态代理对象,将自定义的invocationhandler实例传入
   pro ihello = (pro) constructor.newinstance(new javaproxy(new proxyed()));
   //5.通过代理对象调用目标方法
   ihello.text();
   //第二种,调用jdk提供的方法,实现了2~4步
   proxy.newproxyinstance(javaproxy.class.getclassloader(),proxyed.class.getinterfaces(),new javaproxy(new proxyed()));
  }
}

入口:newproxyinstance

public static object newproxyinstance(classloader loader, class<?>[] interfaces, invocationhandler h) throws illegalargumentexception {
  //objects.requirenonnull 判空方法,之后所有的单纯的判断null并抛异常,都是此方法
  objects.requirenonnull(h);
  //clone 类实现的所有接口
  final class<?>[] intfs = interfaces.clone();
  //获取当前系统安全接口
  final securitymanager sm = system.getsecuritymanager();
  if (sm != null) {
   //reflection.getcallerclass返回调用该方法的方法的调用类;loader:接口的类加载器
   //进行包访问权限、类加载器权限等检查
   checkproxyaccess(reflection.getcallerclass(), loader, intfs);
  }

  /*
   * look up or generate the designated proxy class.
   * 查找或生成代理类
   */
  class<?> cl = getproxyclass0(loader, intfs);

  /*
   * invoke its constructor with the designated invocation handler.
   * 使用指定的调用处理程序调用它的构造函数
   */
  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});
  } catch (illegalaccessexception|instantiationexception e) {
   throw new internalerror(e.tostring(), e);
  } catch (invocationtargetexception e) {
   throwable t = e.getcause();
   if (t instanceof runtimeexception) {
    throw (runtimeexception) t;
   } else {
    throw new internalerror(t.tostring(), t);
   }
  } catch (nosuchmethodexception e) {
   throw new internalerror(e.tostring(), e);
  }
 }

从上面的分析中可以看出,newproxyinstance帮我们执行了生成代理类----获取构造器----生成代理对象这三步;

我们重点分析生成代理类

getproxyclass0

/**
  * a cache of proxy classes:动态代理类的弱缓存容器
  * keyfactory:根据接口的数量,映射一个最佳的key生成函数,其中表示接口的类对象被弱引用;也就是key对象被弱引用继承自weakreference(key0、key1、key2、keyx),保存接口密钥(hash值)
  * proxyclassfactory:生成动态类的工厂
  * 注意,两个都实现了bifunction<classloader, class<?>[], object>接口
  */
 private static final weakcache<classloader, class<?>[], class<?>> proxyclasscache = new weakcache<>(new keyfactory(), new proxyclassfactory());

 /**
  * generate a proxy class. must call the checkproxyaccess method
  * to perform permission checks before calling this.
  * 生成代理类,调用前必须进行 checkproxyaccess权限检查,所以newproxyinstance进行了权限检查
  */
 private static class<?> getproxyclass0(classloader loader, class<?>... interfaces) {
  //实现接口的最大数量<65535;谁写的类能实现这么多接口
  if (interfaces.length > 65535) {
   throw new illegalargumentexception("interface limit exceeded");
  }

  // if the proxy class defined by the given loader implementing
  // the given interfaces exists, this will simply return the cached copy;
  // otherwise, it will create the proxy class via the proxyclassfactory
  // 如果缓存中有,就直接返回,否则会生成
  return proxyclasscache.get(loader, interfaces);
 }

proxyclasscache.get

public v get(k key, p parameter) {
  //key:类加载器;parameter:接口数组
  objects.requirenonnull(parameter);
  //清除已经被gc回收的弱引用
  expungestaleentries();

  //cachekey弱引用类,refqueue已经被回收的弱引用队列;构建一个cachekey
  object cachekey = cachekey.valueof(key, refqueue);
  
  //map一级缓存,获取valuesmap二级缓存
  concurrentmap<object, supplier<v>> valuesmap = map.get(cachekey);
  if (valuesmap == null) {
   concurrentmap<object, supplier<v>> oldvaluesmap
     = map.putifabsent(cachekey,
     valuesmap = new concurrenthashmap<>());
   if (oldvaluesmap != null) {
    valuesmap = oldvaluesmap;
   }
  }

  // subkeyfactory类型是keyfactory,apply返回表示接口的key
  object subkey = objects.requirenonnull(subkeyfactory.apply(key, parameter));
  //factory 实现了supplier,我们实际是获取缓存中的factory,调用其get方法
  supplier<v> supplier = valuesmap.get(subkey);
  factory factory = null;
  
  //下面用到了 cas+重试 实现的多线程安全的 非阻塞算法
  while (true) {
   if (supplier != null) {
    // 只需要知道,最终会调用get方法,此supplier可能是缓存中取出来的,也可能是factory新new出来的
    v value = supplier.get();
    if (value != null) {
     return value;
    }
   }
   // else no supplier in cache
   // or a supplier that returned null (could be a cleared cachevalue
   // or a factory that wasn't successful in installing the cachevalue)

   // lazily construct a factory
   if (factory == null) {
    factory = new factory(key, parameter, subkey, valuesmap);
   }

   if (supplier == null) {
    supplier = valuesmap.putifabsent(subkey, factory);
    if (supplier == null) {
     // successfully installed factory
     supplier = factory;
    }
    // else retry with winning supplier
   } else {
    if (valuesmap.replace(subkey, supplier, factory)) {
     // successfully replaced
     // cleared cacheentry / unsuccessful factory
     // with our factory
     supplier = factory;
    } else {
     // retry with current supplier
     supplier = valuesmap.get(subkey);
    }
   }
  }
 }

supplier.get

这个方法中会调用proxyclassfactory的apply方法,就不过多介绍

proxyclassfactory.apply

public class<?> apply(classloader loader, class<?>[] interfaces) {

  map<class<?>, boolean> interfaceset = new identityhashmap<>(interfaces.length);
  for (class<?> intf : interfaces) {
    /*
     * verify that the class loader resolves the name of this interface to the same class object.
     * 类加载器和接口名解析出的是同一个
     */
   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");
   }
    /*
     * verify that the class object actually represents an interface.
     * 确保是一个接口
     */
   if (!interfaceclass.isinterface()) {
    throw new illegalargumentexception( interfaceclass.getname() + " is not an interface");
   }
    /*
     * verify that this interface is not a duplicate.
     * 确保接口没重复
     */
   if (interfaceset.put(interfaceclass, boolean.true) != null) {
    throw new illegalargumentexception( "repeated interface: " + interfaceclass.getname());
   }
  }

  string proxypkg = null;  // package to define proxy class in
  int accessflags = modifier.public | modifier.final;
   /*
    * record the package of a non-public proxy interface so that the proxy class will be defined in the same package.
    * verify that all non-public proxy interfaces are in the same package.
    * 验证所有非公共的接口在同一个包内;公共的就无需处理
    */
  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) {
   // if no non-public proxy interfaces, use com.sun.proxy package
   proxypkg = reflectutil.proxy_package + ".";
  }
   /*
    * choose a name for the proxy class to generate.
    * proxyclassnameprefix = $proxy
    * nextuniquenumber 是一个原子类,确保多线程安全,防止类名重复,类似于:$proxy0,$proxy1......
    */
  long num = nextuniquenumber.getandincrement();
  string proxyname = proxypkg + proxyclassnameprefix + num;
   /*
    * generate the specified proxy class.
    * 生成类字节码的方法:重点
    */
  byte[] proxyclassfile = proxygenerator.generateproxyclass( proxyname, interfaces, accessflags);
  try {
   return defineclass0(loader, proxyname, proxyclassfile, 0, proxyclassfile.length);
  } catch (classformaterror e) {
    /*
     * a classformaterror here means that (barring bugs in the
     * proxy class generation code) there was some other
     * invalid aspect of the arguments supplied to the proxy
     * class creation (such as virtual machine limitations
     * exceeded).
     */
   throw new illegalargumentexception(e.tostring());
  }
 }

proxygenerator.generateproxyclass

public static byte[] generateproxyclass(final string name, class<?>[] interfaces, int accessflags) {
  proxygenerator gen = new proxygenerator(name, interfaces, accessflags);
  //真正生成字节码的方法
  final byte[] classfile = gen.generateclassfile();
  //如果savegeneratedfiles为true 则生成字节码文件,所以在开始我们要设置这个参数
  //当然,也可以通过返回的bytes自己输出
  if (savegeneratedfiles) {
   java.security.accesscontroller.doprivileged( new java.security.privilegedaction<void>() {
      public void run() {
       try {
        int i = name.lastindexof('.');
        path path;
        if (i > 0) {
         path dir = paths.get(name.substring(0, i).replace('.', file.separatorchar));
         files.createdirectories(dir);
         path = dir.resolve(name.substring(i+1, name.length()) + ".class");
        } else {
         path = paths.get(name + ".class");
        }
        files.write(path, classfile);
        return null;
       } catch (ioexception e) {
        throw new internalerror( "i/o exception saving generated file: " + e);
       }
      }
     });
  }
  return classfile;
 }

最终方法

private byte[] generateclassfile() {
  /* ============================================================
   * step 1: assemble proxymethod objects for all methods to generate proxy dispatching code for.
   * 步骤1:为所有方法生成代理调度代码,将代理方法对象集合起来。
   */
  //增加 hashcode、equals、tostring方法
  addproxymethod(hashcodemethod, object.class);
  addproxymethod(equalsmethod, object.class);
  addproxymethod(tostringmethod, object.class);
  //增加接口方法
  for (class<?> intf : interfaces) {
   for (method m : intf.getmethods()) {
    addproxymethod(m, intf);
   }
  }

  /*
   * 验证方法签名相同的一组方法,返回值类型是否相同;意思就是重写方法要方法签名和返回值一样
   */
  for (list<proxymethod> sigmethods : proxymethods.values()) {
   checkreturntypes(sigmethods);
  }

  /* ============================================================
   * step 2: assemble fieldinfo and methodinfo structs for all of fields and methods in the class we are generating.
   * 为类中的方法生成字段信息和方法信息
   */
  try {
   //增加构造方法
   methods.add(generateconstructor());
   for (list<proxymethod> sigmethods : proxymethods.values()) {
    for (proxymethod pm : sigmethods) {
     // add static field for method's method object
     fields.add(new fieldinfo(pm.methodfieldname,
       "ljava/lang/reflect/method;",
       acc_private | acc_static));
     // generate code for proxy method and add it
     methods.add(pm.generatemethod());
    }
   }
   //增加静态初始化信息
   methods.add(generatestaticinitializer());
  } catch (ioexception e) {
   throw new internalerror("unexpected i/o exception", e);
  }

  if (methods.size() > 65535) {
   throw new illegalargumentexception("method limit exceeded");
  }
  if (fields.size() > 65535) {
   throw new illegalargumentexception("field limit exceeded");
  }

  /* ============================================================
   * step 3: write the final class file.
   * 步骤3:编写最终类文件
   */
  /*
   * make sure that constant pool indexes are reserved for the following items before starting to write the final class file.
   * 在开始编写最终类文件之前,确保为下面的项目保留常量池索引。
   */
  cp.getclass(dottoslash(classname));
  cp.getclass(superclassname);
  for (class<?> intf: interfaces) {
   cp.getclass(dottoslash(intf.getname()));
  }

  /*
   * disallow new constant pool additions beyond this point, since we are about to write the final constant pool table.
   * 设置只读,在这之前不允许在常量池中增加信息,因为要写常量池表
   */
  cp.setreadonly();

  bytearrayoutputstream bout = new bytearrayoutputstream();
  dataoutputstream dout = new dataoutputstream(bout);

  try {
   // u4 magic;
   dout.writeint(0xcafebabe);
   // u2 次要版本;
   dout.writeshort(classfile_minor_version);
   // u2 主版本
   dout.writeshort(classfile_major_version);

   cp.write(dout);    // (write constant pool)

   // u2 访问标识;
   dout.writeshort(accessflags);
   // u2 本类名;
   dout.writeshort(cp.getclass(dottoslash(classname)));
   // u2 父类名;
   dout.writeshort(cp.getclass(superclassname));
   // u2 接口;
   dout.writeshort(interfaces.length);
   // u2 interfaces[interfaces_count];
   for (class<?> intf : interfaces) {
    dout.writeshort(cp.getclass(
      dottoslash(intf.getname())));
   }
   // u2 字段;
   dout.writeshort(fields.size());
   // field_info fields[fields_count];
   for (fieldinfo f : fields) {
    f.write(dout);
   }
   // u2 方法;
   dout.writeshort(methods.size());
   // method_info methods[methods_count];
   for (methodinfo m : methods) {
    m.write(dout);
   }
   // u2 类文件属性:对于代理类来说没有类文件属性;
   dout.writeshort(0); // (no classfile attributes for proxy classes)

  } catch (ioexception e) {
   throw new internalerror("unexpected i/o exception", e);
  }

  return bout.tobytearray();
 }

生成的字节码反编译

final class $proxy0 extends proxy implements pro {
  //fields 
  private static method m1;
  private static method m2;
  private static method m3;
  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})).booleanvalue();
   } catch (runtimeexception | error var3) {
    throw var3;
   } catch (throwable var4) {
    throw new undeclaredthrowableexception(var4);
   }
  }

  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 void text() throws {
   try {
    //实际就是调用代理类的invoke方法 
    super.h.invoke(this, m3, (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)).intvalue();
   } catch (runtimeexception | error var2) {
    throw var2;
   } catch (throwable var3) {
    throw new undeclaredthrowableexception(var3);
   }
  }

  static {
   try {
    //这里每个方法对象 和类的实际方法绑定
    m1 = class.forname("java.lang.object").getmethod("equals", new class[]{class.forname("java.lang.object")});
    m2 = class.forname("java.lang.object").getmethod("tostring", new class[0]);
    m3 = class.forname("spring.commons.api.study.createmodel.pro").getmethod("text", new class[0]);
    m0 = class.forname("java.lang.object").getmethod("hashcode", new class[0]);
   } catch (nosuchmethodexception var2) {
    throw new nosuchmethoderror(var2.getmessage());
   } catch (classnotfoundexception var3) {
    throw new noclassdeffounderror(var3.getmessage());
   }
  }
 }

以上这篇java 1.8 动态代理源码深度分析就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

上一篇:

下一篇: