1. 图解

上图主要描述了JDK动态代理的执行过程,下面做详细分析。

2. Proxy源码分析

上一篇,在使用JDK动态代理的时候,借助于Proxy类,使用newProxyInstance静态方法,创建了动态代理对象,这个方法接收三个参数,分别是目标类的类加载器、目标类实现的接口数组、自定义的InvocationHandler类,下面从该方法开始,详细分析该类如何生成的。本文所用JDK版本为1.8.0_161,为了保留源码英文注释的原汁原味,未对英文注释做删减,并在代码后面加注中文注释。

  1. public static Object newProxyInstance(ClassLoader loader,
  2. Class<?>[] interfaces,
  3. InvocationHandler h)
  4. throws IllegalArgumentException
  5. {
  6. Objects.requireNonNull(h);// 验证InvocationHandler不为空
  7. final Class<?>[] intfs = interfaces.clone(); // 克隆代理类实现的所有接口
  8. final SecurityManager sm = System.getSecurityManager(); //获取安全管理器
  9. if (sm != null) {
  10. checkProxyAccess(Reflection.getCallerClass(), loader, intfs); //进行一些权限检验
  11. }
  12. /*
  13. * Look up or generate the designated proxy class.
  14. */
  15. Class<?> cl = getProxyClass0(loader, intfs); // 查找或创建指定的代理对象
  16. /*
  17. * Invoke its constructor with the designated invocation handler.
  18. */
  19. try {
  20. if (sm != null) {
  21. checkNewProxyPermission(Reflection.getCallerClass(), cl); //进行一些权限检验
  22. }
  23. final Constructor<?> cons = cl.getConstructor(constructorParams); //获取参数类型是InvocationHandler.class的代理类构造器
  24. final InvocationHandler ih = h;
  25. if (!Modifier.isPublic(cl.getModifiers())) { //如果代理类是不可访问的, 就使用特权将它的构造器设置为可访问
  26. AccessController.doPrivileged(new PrivilegedAction<Void>() {
  27. public Void run() {
  28. cons.setAccessible(true);
  29. return null;
  30. }
  31. });
  32. }
  33. return cons.newInstance(new Object[]{h}); //传入InvocationHandler实例去构造一个代理类的实例
  34. } catch (IllegalAccessException|InstantiationException e) {
  35. throw new InternalError(e.toString(), e);
  36. } catch (InvocationTargetException e) {
  37. Throwable t = e.getCause();
  38. if (t instanceof RuntimeException) {
  39. throw (RuntimeException) t;
  40. } else {
  41. throw new InternalError(t.toString(), t);
  42. }
  43. } catch (NoSuchMethodException e) {
  44. throw new InternalError(e.toString(), e);
  45. }
  46. }

从上面代码可以看出,创建代理对象总共如下几步:

  1. 对参数进行一些权限校验;
  2. getProxyClass0方法生成了代理类的类对象;
  3. 获取参数类型是InvocationHandler.class的代理类构造器;
  4. 通过InvocationHandler实例的引用,去构造出一个代理类对象。

因为生成的代理类继承自Proxy类,子类创建实例对象时,会优先调用父类Proxy的构造,所以最后会调用Proxy的构造器将InvocationHandler将引用传入。

下面重点看getProxyClass0方法是如何获取代理对象的。

  1. private static Class<?> getProxyClass0(ClassLoader loader,
  2. Class<?>... interfaces) {
  3. if (interfaces.length > 65535) {
  4. throw new IllegalArgumentException("interface limit exceeded");
  5. }
  6. // If the proxy class defined by the given loader implementing
  7. // the given interfaces exists, this will simply return the cached copy;
  8. // otherwise, it will create the proxy class via the ProxyClassFactory
  9. return proxyClassCache.get(loader, interfaces); // 如果实现给定接口的给定加载器所定义的代理类存在,则从缓存取,否则通过ProxyClassFactory创建
  10. }

上述代码主要做了两件事:

  1. 判断代理类实现的接口不能大于65535这个数;
  2. 缓存存在代理类,则从缓存取,否则从ProxyClassFactory创建。

3. WeakCache源码

下面将继续深入WeakCache的源码,分析proxyClassCache.get方法相关实现。

  1. final class WeakCache<K, P, V> {
  2. private final ReferenceQueue<K> refQueue
  3. = new ReferenceQueue<>(); // Reference引用队列
  4. // the key type is Object for supporting null key
  5. private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map //缓存的底层实现, key为一级缓存, value为二级缓存。 为了支持null, map的key类型设置为Object
  6. = new ConcurrentHashMap<>();
  7. private final ConcurrentMap<Supplier<V>, Boolean> reverseMap // 记录了所有代理类生成器是否可用, 这是为了实现缓存的过期机制
  8. = new ConcurrentHashMap<>();
  9. private final BiFunction<K, P, ?> subKeyFactory; //生成二级缓存key的工厂, 这里传入的是KeyFactory
  10. private final BiFunction<K, P, V> valueFactory; //生成二级缓存value的工厂, 这里传入的是ProxyClassFactory
  11. /**
  12. * Construct an instance of {@code WeakCache}
  13. *
  14. * @param subKeyFactory a function mapping a pair of
  15. * {@code (key, parameter) -> sub-key}
  16. * @param valueFactory a function mapping a pair of
  17. * {@code (key, parameter) -> value}
  18. * @throws NullPointerException if {@code subKeyFactory} or
  19. * {@code valueFactory} is null.
  20. */
  21. public WeakCache(BiFunction<K, P, ?> subKeyFactory, //构造器, 传入生成二级缓存key的工厂和生成二级缓存value的工厂
  22. BiFunction<K, P, V> valueFactory) {
  23. this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
  24. this.valueFactory = Objects.requireNonNull(valueFactory);
  25. }
  26. /**
  27. * Look-up the value through the cache. This always evaluates the
  28. * {@code subKeyFactory} function and optionally evaluates
  29. * {@code valueFactory} function if there is no entry in the cache for given
  30. * pair of (key, subKey) or the entry has already been cleared.
  31. *
  32. * @param key possibly null key
  33. * @param parameter parameter used together with key to create sub-key and
  34. * value (should not be null)
  35. * @return the cached value (never null)
  36. * @throws NullPointerException if {@code parameter} passed in or
  37. * {@code sub-key} calculated by
  38. * {@code subKeyFactory} or {@code value}
  39. * calculated by {@code valueFactory} is null.
  40. */
  41. public V get(K key, P parameter) {
  42. Objects.requireNonNull(parameter); //这里要求实现的接口不能为空
  43. expungeStaleEntries(); //清除过期的缓存
  44. Object cacheKey = CacheKey.valueOf(key, refQueue); //将ClassLoader包装成CacheKey, 作为一级缓存的key
  45. // lazily install the 2nd level valuesMap for the particular cacheKey
  46. ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); // 懒加载获取二级缓存
  47. if (valuesMap == null) { //如果根据ClassLoader没有获取到对应的值
  48. ConcurrentMap<Object, Supplier<V>> oldValuesMap // 如果不存在则放入,否则返回原先的值
  49. = map.putIfAbsent(cacheKey,
  50. valuesMap = new ConcurrentHashMap<>());
  51. if (oldValuesMap != null) { //如果oldValuesMap有值, 说明放入失败
  52. valuesMap = oldValuesMap;
  53. }
  54. }
  55. // create subKey and retrieve the possible Supplier<V> stored by that
  56. // subKey from valuesMap
  57. Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); //根据代理类实现的接口数组来生成二级缓存key, 分为key0, key1, key2, keyx
  58. Supplier<V> supplier = valuesMap.get(subKey); //这里通过subKey获取到二级缓存的值
  59. Factory factory = null;
  60. while (true) { //这个循环提供了轮询机制, 如果条件为假就继续重试直到条件为真为止
  61. if (supplier != null) {
  62. // supplier might be a Factory or a CacheValue<V> instance
  63. V value = supplier.get(); // 在这里supplier可能是一个Factory也可能会是一个CacheValue
  64. if (value != null) {
  65. return value;
  66. }
  67. }
  68. // else no supplier in cache
  69. // or a supplier that returned null (could be a cleared CacheValue
  70. // or a Factory that wasn't successful in installing the CacheValue)
  71. // lazily construct a Factory
  72. if (factory == null) { //缓存中没有supplier
  73. factory = new Factory(key, parameter, subKey, valuesMap); //新建一个Factory实例作为subKey对应的值
  74. }
  75. if (supplier == null) { // supplier返回null
  76. supplier = valuesMap.putIfAbsent(subKey, factory); //到这里表明subKey没有对应的值, 就将factory作为subKey的值放入
  77. if (supplier == null) {
  78. // successfully installed Factory
  79. supplier = factory; //到这里表明成功将factory放入缓存
  80. }
  81. // else retry with winning supplier
  82. } else { //Factory 没有成功装入缓存
  83. if (valuesMap.replace(subKey, supplier, factory)) { //期间可能其他线程修改了值, 那么就将原先的值替换
  84. // successfully replaced
  85. // cleared CacheEntry / unsuccessful Factory
  86. // with our Factory
  87. supplier = factory; //成功将factory替换成新的值
  88. } else {
  89. // retry with current supplier
  90. supplier = valuesMap.get(subKey); //替换失败, 继续使用原先的值
  91. }
  92. }
  93. }
  94. }
  95. //后面省略

WeakCache的成员变量map,是通过ConcurrentMap来完成的,key为一级缓存, value为二级缓存,类型也是ConcurrentMapreverseMap是为了实现缓存的过期机制;subKeyFactory是二级缓存key的生成工厂,通过构造器传入Proxy类的KeyFactoryvalueFactory是二级缓存value的生成工厂,通过构造器传入Proxy类的ProxyClassFactory

get方法大致做了如下几步:

  1. ClassLoader包装成CacheKey, 作为一级缓存的key
  2. 懒加载获取二级缓存valuesMap
  3. 根据代理类实现的接口数组来生成二级缓存subKey
  4. 这里通过二级缓存的subKey获取到二级缓存的值;
  5. 若缓存中没有值、或者返回null、或者Factory实例没有成功装载,通过轮询方式获取二级缓存的值,直到缓存的值被装载进去。

这里的二级缓存的值是一个Factory实例,最终代理类的值是通过Factory这个工厂来获得的。

  1. /**
  2. * A factory {@link Supplier} that implements the lazy synchronized
  3. * construction of the value and installment of it into the cache.
  4. */
  5. private final class Factory implements Supplier<V> {
  6. private final K key; //一级缓存key, 根据ClassLoader生成
  7. private final P parameter; //代理类实现的接口数组
  8. private final Object subKey; //二级缓存key, 根据接口数组生成
  9. private final ConcurrentMap<Object, Supplier<V>> valuesMap; //二级缓存
  10. Factory(K key, P parameter, Object subKey,
  11. ConcurrentMap<Object, Supplier<V>> valuesMap) {
  12. this.key = key;
  13. this.parameter = parameter;
  14. this.subKey = subKey;
  15. this.valuesMap = valuesMap;
  16. }
  17. @Override
  18. public synchronized V get() { // serialize access
  19. // re-check
  20. Supplier<V> supplier = valuesMap.get(subKey); //再次检查并获取二级缓存里面的Supplier, 用来验证是否是Factory本身
  21. if (supplier != this) { //在这里验证supplier是否是Factory实例本身, 如果不是则返回null让调用者继续轮询重试;
  22. // something changed while we were waiting:
  23. // might be that we were replaced by a CacheValue
  24. // or were removed because of failure ->
  25. // return null to signal WeakCache.get() to retry
  26. // the loop
  27. return null;
  28. }
  29. // else still us (supplier == this)
  30. // create new value
  31. V value = null;
  32. try {
  33. value = Objects.requireNonNull(valueFactory.apply(key, parameter)); // 通过valueFactory生成代理类, 实际传入ProxyClassFactory去生成代理类
  34. } finally {
  35. if (value == null) { // remove us on failure
  36. valuesMap.remove(subKey, this); //如果生成代理类失败, 就将这个二级缓存删除
  37. }
  38. }
  39. // the only path to reach here is with non-null value
  40. assert value != null; //只有value的值不为空才能到达这里
  41. // wrap value with CacheValue (WeakReference)
  42. CacheValue<V> cacheValue = new CacheValue<>(value); //使用弱引用包装生成的代理类
  43. // put into reverseMap
  44. reverseMap.put(cacheValue, Boolean.TRUE); //将包装后的cacheValue作为可用的代理类,放入reverseMap中
  45. // try replacing us with CacheValue (this should always succeed)
  46. if (!valuesMap.replace(subKey, this, cacheValue)) { //将包装后的cacheValue放入二级缓存中, 这个操作必须成功, 否则就报错
  47. throw new AssertionError("Should not reach here");
  48. }
  49. // successfully replaced us with new CacheValue -> return the value
  50. // wrapped by it
  51. return value; //最后返回未被弱引用包装的原始代理类value
  52. }
  53. }

内部类Factoryget方法是使用synchronized关键字进行了同步,主要做了如下几步:

  1. 检查并获取二级缓存里面的Supplier, 验证是否是Factory本身;
  2. 如果1不是,则返回null,让调用者继续轮询重试;
  3. 如果1是,则通过valueFactory生成代理类, 实际传入ProxyClassFactory去生成代理类;
  4. 如果生成代理类失败, 就将这个二级缓存删除;
  5. 断言,只有代理类生成成功才能继续下面步骤;
  6. 使用弱引用包装生成的代理类;
  7. 将包装后的cacheValue作为可用的代理类,放入reverseMap中;
  8. 将包装后的cacheValue放入二级缓存中, 且操作必须成功;
  9. 最后返回未被弱引用包装的原始代理类value

至此,WeakCache一级缓存和二级缓存实现的原理,已经阐述清楚,上述过程中的第3步,二级缓存key生成的原理,是怎样通过Proxy的内部类ProxyClassFactory来生成代理类的,下面继续深入ProxyGenerator这个类,分享代理类的字节码生成过程。

4. ProxyClassFactory源码分析

  1. /**
  2. * A factory function that generates, defines and returns the proxy class given
  3. * the ClassLoader and array of interfaces.
  4. */
  5. private static final class ProxyClassFactory
  6. implements BiFunction<ClassLoader, Class<?>[], Class<?>>
  7. {
  8. // prefix for all proxy class names
  9. private static final String proxyClassNamePrefix = "$Proxy"; // 所有代理类名称的前缀
  10. // next number to use for generation of unique proxy class names
  11. private static final AtomicLong nextUniqueNumber = new AtomicLong(); // 用原子类来生成代理类的序号, 生成唯一的代理类名称
  12. @Override
  13. public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
  14. Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
  15. for (Class<?> intf : interfaces) {
  16. /*
  17. * Verify that the class loader resolves the name of this
  18. * interface to the same Class object.
  19. */
  20. Class<?> interfaceClass = null;
  21. try {
  22. interfaceClass = Class.forName(intf.getName(), false, loader);
  23. } catch (ClassNotFoundException e) {
  24. }
  25. if (interfaceClass != intf) { // intf是否可以由指定的类加载进行加载
  26. throw new IllegalArgumentException(
  27. intf + " is not visible from class loader");
  28. }
  29. /*
  30. * Verify that the Class object actually represents an
  31. * interface.
  32. */
  33. if (!interfaceClass.isInterface()) { // intf是否是一个接口
  34. throw new IllegalArgumentException(
  35. interfaceClass.getName() + " is not an interface");
  36. }
  37. /*
  38. * Verify that this interface is not a duplicate.
  39. */
  40. if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { // intf在数组中是否有重复
  41. throw new IllegalArgumentException(
  42. "repeated interface: " + interfaceClass.getName());
  43. }
  44. }
  45. String proxyPkg = null; // package to define proxy class in //生成代理类的包名
  46. int accessFlags = Modifier.PUBLIC | Modifier.FINAL; //生成代理类的访问标志, 默认是public final的
  47. /*
  48. * Record the package of a non-public proxy interface so that the
  49. * proxy class will be defined in the same package. Verify that
  50. * all non-public proxy interfaces are in the same package.
  51. */
  52. for (Class<?> intf : interfaces) {
  53. int flags = intf.getModifiers(); //获取接口的访问标志
  54. if (!Modifier.isPublic(flags)) { //如果接口的访问标志不是public, 那么生成代理类的包名和接口包名相同
  55. accessFlags = Modifier.FINAL; //生成的代理类的访问标志设置为final
  56. String name = intf.getName(); //获取接口全限定名
  57. int n = name.lastIndexOf('.');
  58. String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
  59. if (proxyPkg == null) {
  60. proxyPkg = pkg; //生成的代理类的包名和接口包名是一样的
  61. } else if (!pkg.equals(proxyPkg)) { //代理类如果实现不同包的接口, 并且接口都不是public的, 那么就会在这里报错
  62. throw new IllegalArgumentException(
  63. "non-public interfaces from different packages");
  64. }
  65. }
  66. }
  67. if (proxyPkg == null) {
  68. // if no non-public proxy interfaces, use com.sun.proxy package
  69. proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; //如果接口访问标志都是public的话, 那生成的代理类都放到默认的包下:com.sun.proxy
  70. }
  71. /*
  72. * Choose a name for the proxy class to generate.
  73. */
  74. long num = nextUniqueNumber.getAndIncrement(); //生成代理类的序号
  75. String proxyName = proxyPkg + proxyClassNamePrefix + num; //生成代理类的全限定名, 包名+前缀+序号, 例如:com.sun.proxy.$Proxy0
  76. /*
  77. * Generate the specified proxy class.
  78. */
  79. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
  80. proxyName, interfaces, accessFlags); // 用ProxyGenerator来生成字节码, 该类放在sun.misc包下
  81. try {
  82. return defineClass0(loader, proxyName,
  83. proxyClassFile, 0, proxyClassFile.length); //根据二进制文件生成相应的Class实例
  84. } catch (ClassFormatError e) {
  85. /*
  86. * A ClassFormatError here means that (barring bugs in the
  87. * proxy class generation code) there was some other
  88. * invalid aspect of the arguments supplied to the proxy
  89. * class creation (such as virtual machine limitations
  90. * exceeded).
  91. */
  92. throw new IllegalArgumentException(e.toString());
  93. }
  94. }
  95. }

上述代码主要完成以下步骤:

  1. 判断接口是否由指定类的加载器加载、是否是接口、接口是否重复;
  2. 指定生成包名类名的相关规则,接口访问标志都是public,代理类都放到默认的com.sun.proxy包下,接口的访问标志不是public, 那么生成代理类的包名和接口包名相同;
  3. 通过ProxyGenerator类的generateProxyClass方法生成字节码文件;
  4. 根据二进制文件生成相应的代理类实例。

    第3步是关键,下面将进一步分析ProxyGenerator类的generateProxyClass方法。

5. ProxyGenerator源码分析

由于ProxyGenerator类不在jdk中,需要下载openjdk才能看到源码,openjdk1.8官网下载地址如下http://hg.openjdk.java.net/jdk8/jdk8/jdk/archive/tip.zip,解压后在openjdk\jdk\src\share\classes\sun\misc下面。

  1. /**
  2. * Generate a class file for the proxy class. This method drives the
  3. * class file generation process.
  4. */
  5. private byte[] generateClassFile() {
  6. /* ============================================================
  7. * Step 1: Assemble ProxyMethod objects for all methods to
  8. * generate proxy dispatching code for.
  9. */
  10. //第一步, 将所有的方法组装成ProxyMethod对象
  11. /*
  12. * Record that proxy methods are needed for the hashCode, equals,
  13. * and toString methods of java.lang.Object. This is done before
  14. * the methods from the proxy interfaces so that the methods from
  15. * java.lang.Object take precedence over duplicate methods in the
  16. * proxy interfaces.
  17. */
  18. addProxyMethod(hashCodeMethod, Object.class); //为代理类生成hashCode代理方法
  19. addProxyMethod(equalsMethod, Object.class); //为代理类生成equals代理方法
  20. addProxyMethod(toStringMethod, Object.class); //为代理类生成toString代理方法
  21. /*
  22. * Now record all of the methods from the proxy interfaces, giving
  23. * earlier interfaces precedence over later ones with duplicate
  24. * methods.
  25. */
  26. for (Class<?> intf : interfaces) { //遍历每一个接口的每一个方法, 并且为其生成ProxyMethod对象
  27. for (Method m : intf.getMethods()) {
  28. addProxyMethod(m, intf);
  29. }
  30. }
  31. /*
  32. * For each set of proxy methods with the same signature,
  33. * verify that the methods' return types are compatible.
  34. */
  35. for (List<ProxyMethod> sigmethods : proxyMethods.values()) { //对于具有相同签名的代理方法, 检验方法的返回值是否兼容
  36. checkReturnTypes(sigmethods);
  37. }
  38. /* ============================================================
  39. * Step 2: Assemble FieldInfo and MethodInfo structs for all of
  40. * fields and methods in the class we are generating.
  41. */ //第二步, 组装要生成的class文件的所有的字段信息和方法信息
  42. try {
  43. methods.add(generateConstructor()); //添加构造器方法
  44. for (List<ProxyMethod> sigmethods : proxyMethods.values()) { //遍历缓存中的代理方法
  45. for (ProxyMethod pm : sigmethods) {
  46. // add static field for method's Method object
  47. fields.add(new FieldInfo(pm.methodFieldName, //添加代理类的静态字段
  48. "Ljava/lang/reflect/Method;",
  49. ACC_PRIVATE | ACC_STATIC));
  50. // generate code for proxy method and add it
  51. methods.add(pm.generateMethod()); //添加代理类的代理方法
  52. }
  53. }
  54. methods.add(generateStaticInitializer()); //添加代理类的静态字段初始化方法
  55. } catch (IOException e) {
  56. throw new InternalError("unexpected I/O Exception", e);
  57. }
  58. if (methods.size() > 65535) { //验证方法和字段集合不能大于65535
  59. throw new IllegalArgumentException("method limit exceeded");
  60. }
  61. if (fields.size() > 65535) {
  62. throw new IllegalArgumentException("field limit exceeded");
  63. }
  64. /* ============================================================
  65. * Step 3: Write the final class file.
  66. */
  67. //第三步, 写入最终的class文件
  68. /*
  69. * Make sure that constant pool indexes are reserved for the
  70. * following items before starting to write the final class file.
  71. */
  72. cp.getClass(dotToSlash(className)); //验证常量池中存在代理类的全限定名
  73. cp.getClass(superclassName); //验证常量池中存在代理类父类的全限定名, 父类名为:"java/lang/reflect/Proxy"
  74. for (Class<?> intf: interfaces) { //验证常量池存在代理类接口的全限定名
  75. cp.getClass(dotToSlash(intf.getName()));
  76. }
  77. /*
  78. * Disallow new constant pool additions beyond this point, since
  79. * we are about to write the final constant pool table.
  80. */
  81. cp.setReadOnly(); //接下来要开始写入文件了,设置常量池只读
  82. ByteArrayOutputStream bout = new ByteArrayOutputStream();
  83. DataOutputStream dout = new DataOutputStream(bout);
  84. try {
  85. /*
  86. * Write all the items of the "ClassFile" structure.
  87. * See JVMS section 4.1.
  88. */
  89. // u4 magic;
  90. dout.writeInt(0xCAFEBABE); //1.写入魔数
  91. // u2 minor_version;
  92. dout.writeShort(CLASSFILE_MINOR_VERSION); //2.写入次版本号
  93. // u2 major_version;
  94. dout.writeShort(CLASSFILE_MAJOR_VERSION); //3.写入主版本号
  95. cp.write(dout); // (write constant pool) //4.写入常量池
  96. // u2 access_flags;
  97. dout.writeShort(accessFlags); //5.写入访问修饰符
  98. // u2 this_class;
  99. dout.writeShort(cp.getClass(dotToSlash(className))); //6.写入类索引
  100. // u2 super_class;
  101. dout.writeShort(cp.getClass(superclassName)); //7.写入父类索引, 生成的代理类都继承自Proxy
  102. // u2 interfaces_count;
  103. dout.writeShort(interfaces.length); //8.写入接口计数值
  104. // u2 interfaces[interfaces_count];
  105. for (Class<?> intf : interfaces) {
  106. dout.writeShort(cp.getClass( //9.写入接口集合
  107. dotToSlash(intf.getName())));
  108. }
  109. // u2 fields_count;
  110. dout.writeShort(fields.size()); //10.写入字段计数值
  111. // field_info fields[fields_count];
  112. for (FieldInfo f : fields) {
  113. f.write(dout); //11.写入字段集合
  114. }
  115. // u2 methods_count;
  116. dout.writeShort(methods.size());//12.写入方法计数值
  117. // method_info methods[methods_count];
  118. for (MethodInfo m : methods) {
  119. m.write(dout); //13.写入方法集合
  120. }
  121. // u2 attributes_count;
  122. dout.writeShort(0); // (no ClassFile attributes for proxy classes) //14.写入属性计数值, 代理类class文件没有属性所以为0
  123. } catch (IOException e) {
  124. throw new InternalError("unexpected I/O Exception", e);
  125. }
  126. return bout.toByteArray(); //转换成二进制数组输出
  127. }

上述代码主要完成以下步骤:

  1. 收集所有要生成的代理方法,将其包装成ProxyMethod对象并注册到Map集合中;
  2. 收集所有要为Class文件生成的字段信息和方法信息;
  3. 完成了上面的工作后,开始组装Class文件。

    其中第2步是核心,为代理类生成字段和方法,完成以下步骤:

    1.为代理类生成一个带参构造器,传入InvocationHandler实例的引用并调用父类的带参构造器;

    2.遍历代理方法Map集合,为每个代理方法生成对应的Method类型静态域,并将其添加到fields集合中;

    3.遍历代理方法Map集合,为每个代理方法生成对应的MethodInfo对象,并将其添加到methods集合中;

    4.为代理类生成静态初始化方法,该静态初始化方法主要是将每个代理方法的引用赋值给对应的静态字段。

    最终引用上一篇的例子,生成的代理类如下:
  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5. package com.sun.proxy;
  6. import com.wzj.proxy.v9.Sellalbe;
  7. import java.lang.reflect.InvocationHandler;
  8. import java.lang.reflect.Method;
  9. import java.lang.reflect.Proxy;
  10. import java.lang.reflect.UndeclaredThrowableException;
  11. public final class $Proxy0 extends Proxy implements Sellalbe {
  12. private static Method m1;
  13. private static Method m3;
  14. private static Method m2;
  15. private static Method m0;
  16. public $Proxy0(InvocationHandler var1) throws {
  17. super(var1);
  18. }
  19. public final boolean equals(Object var1) throws {
  20. try {
  21. return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
  22. } catch (RuntimeException | Error var3) {
  23. throw var3;
  24. } catch (Throwable var4) {
  25. throw new UndeclaredThrowableException(var4);
  26. }
  27. }
  28. public final void secKill() throws {
  29. try {
  30. super.h.invoke(this, m3, (Object[])null);
  31. } catch (RuntimeException | Error var2) {
  32. throw var2;
  33. } catch (Throwable var3) {
  34. throw new UndeclaredThrowableException(var3);
  35. }
  36. }
  37. public final String toString() throws {
  38. try {
  39. return (String)super.h.invoke(this, m2, (Object[])null);
  40. } catch (RuntimeException | Error var2) {
  41. throw var2;
  42. } catch (Throwable var3) {
  43. throw new UndeclaredThrowableException(var3);
  44. }
  45. }
  46. public final int hashCode() throws {
  47. try {
  48. return (Integer)super.h.invoke(this, m0, (Object[])null);
  49. } catch (RuntimeException | Error var2) {
  50. throw var2;
  51. } catch (Throwable var3) {
  52. throw new UndeclaredThrowableException(var3);
  53. }
  54. }
  55. static {
  56. try {
  57. m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
  58. m3 = Class.forName("com.wzj.proxy.v9.Sellalbe").getMethod("secKill");
  59. m2 = Class.forName("java.lang.Object").getMethod("toString");
  60. m0 = Class.forName("java.lang.Object").getMethod("hashCode");
  61. } catch (NoSuchMethodException var2) {
  62. throw new NoSuchMethodError(var2.getMessage());
  63. } catch (ClassNotFoundException var3) {
  64. throw new NoClassDefFoundError(var3.getMessage());
  65. }
  66. }
  67. }

到此为止,JDK动态代理的生成原理基本上分析完了,笔者通过多次调试源码,并结合英文注解,理解并翻译其中的主要步骤,读者可以根据本文的分析,自己调试JDK源码,相信也会有不一样的收获,文章如有分析不恰当之处,欢迎交流,一起进步。

【趣味设计模式系列】之【代理模式2--JDK动态代理源码解析】的更多相关文章

  1. JDK动态代理源码解析

    动态代理.静态代理优缺点     关于JDK的动态代理,最为人熟知的可能要数Spring AOP的实现,默认情况下,Spring AOP的实现对于接口来说就是使用的JDK的动态代理来实现的,而对于类的 ...

  2. 【趣味设计模式系列】之【代理模式3--Cglib动态代理源码解析】

    1. 图解 上图主要描述了Cglib动态代理的主要执行过程,下面做详细分析,以下源码使用的Cglib版本为3.2.12. 2. Enhancer源码分析 public Object create() ...

  3. 动态代理学习(二)JDK动态代理源码分析

    上篇文章我们学习了如何自己实现一个动态代理,这篇文章我们从源码角度来分析下JDK的动态代理 先看一个Demo: public class MyInvocationHandler implements ...

  4. 设计模式之JDK动态代理源码分析

    这里查看JDK1.8.0_65的源码,通过debug学习JDK动态代理的实现原理 大概流程 1.为接口创建代理类的字节码文件 2.使用ClassLoader将字节码文件加载到JVM 3.创建代理类实例 ...

  5. JDK动态代理源码学习

    继上一篇博客设计模式之代理模式学习之后http://blog.csdn.net/u014427391/article/details/75115928,本博客介绍JDK动态代理的实现原理,学习一下JD ...

  6. jdk 动态代理源码分析

    闲来无事,撸撸源码 使用方法 直接看代码吧.. package com.test.demo.proxy; import java.lang.reflect.InvocationHandler; imp ...

  7. JDK动态代理源码分析

    先抛出一个问题,JDK的动态代理为什么不支持对实现类的代理,只支持接口的代理??? 首先来看一下如何使用JDK动态代理.JDK提供了Java.lang.reflect.Proxy类来实现动态代理的,可 ...

  8. 深入剖析JDK动态代理源码实现

    动态代理.静态代理优缺点优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性.这是代理的共有优点.动态代理只有在用到被代理对象的时候才会对被代理类进行类加载. 而静态代理在编译器就已经开始占内存了 ...

  9. JDK动态代理源码剖析

    关键代码: 1.Proxy.newInstance: private static final Class<?>[] constructorParams = { InvocationHan ...

随机推荐

  1. Centos7安装ftp服务

    本文介绍的ftp是可以使用匿名用户登录,且默认路径是根路径,私人使用非常方便,公开使用具有一定的风险,不安全. # .安装 yum install -y vsftpd # .配置 vim /etc/v ...

  2. idea中maven导入依赖报红的解决办法

    使用idea创建maven项目,maven导入依赖报红,从以下几个步骤排查解决问题: 1.首先查看maven的安装和配置有没有问题.那么,要看那些内容呢.maven的安装位置.maven的settin ...

  3. Python网络数据采集PDF高清完整版免费下载|百度云盘

    百度云盘:Python网络数据采集PDF高清完整版免费下载 提取码:1vc5   内容简介 本书采用简洁强大的Python语言,介绍了网络数据采集,并为采集新式网络中的各种数据类型提供了全面的指导.第 ...

  4. nginx访问日志分析,筛选时间大于1秒的请求

    处理nginx访问日志,筛选时间大于1秒的请求   #!/usr/bin/env python ''' 处理访问日志,筛选时间大于1秒的请求 ''' with open('test.log','a+' ...

  5. js控制语句练习(回顾)

    1.一个小球从100米空中落下,每次反弹一半高度,小球总共经过多少米,请问第10次反弹的高度是多少? //定义初始下落过程高度 var sum1= 0; //定义初始上升高度 var sum2= 0; ...

  6. SQL Server跟踪工具Profiler的使用

    一.什么是SQL Profiler SQL Server Profiler 是一个功能丰富的界面,用于创建和管理跟踪并分析和重播跟踪结果. 事件保存在一个跟踪文件中,稍后试图诊断问题时,可以对该文件进 ...

  7. Apache Tomcat/8.5.51 secretRequired="true"

    1.报错IllegalArgumentException: The AJP Connector is configured with secretRequired="true" b ...

  8. Day12_搜索过滤

    学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"乐优商城"获取视频和教程资料! b站在线视频 0.学习 ...

  9. Python List list()方法

    描述 list() 方法用于将元组转换为列表.高佣联盟 www.cgewang.com 注:元组与列表是非常类似的,区别在于元组的元素值不能修改,元组是放在括号中,列表是放于方括号中. 语法 list ...

  10. 2020牛客暑假多校训练营 第二场 E Exclusive OR FWT

    LINK:Exclusive OR 没做出 原因前面几篇说过了. 根据线性基的知识容易推出 不超过\(w=log Mx\)个数字即可拼出最大值 其中Mx为值域. 那么考虑w+2个数字显然也为最大值.. ...