当前位置: 移动技术网 > IT编程>开发语言>Java > java 1.8 动态代理源码深度分析

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

2019年07月22日  | 移动技术网IT编程  | 我要评论
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 动态代理源码深度分析就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持移动技术网。

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网