zoukankan      html  css  js  c++  java
  • JDK动态代理源码学习

    一、使用示例:

    1、定义DTO:

     1 public class User {
     2 
     3     private String userName;
     4 
     5     private String passWord;
     6 
     7     private String email;
     8 
     9     public String getUserName() {
    10         return userName;
    11     }
    12 
    13     public void setUserName(String userName) {
    14         this.userName = userName;
    15     }
    16 
    17     public String getPassWord() {
    18         return passWord;
    19     }
    20 
    21     public void setPassWord(String passWord) {
    22         this.passWord = passWord;
    23     }
    24 
    25     public String getEmail() {
    26         return email;
    27     }
    28 
    29     public void setEmail(String email) {
    30         this.email = email;
    31     }
    32 }

    2、定义接口: 

    1 public interface UserDao {
    2 
    3     void addUser(User user);
    4 }

    3、实现接口:  

    1 public class UserDaoImpl implements UserDao {
    2 
    3     @Override
    4     public void addUser(User user) {
    5         System.out.println("connect to mySQL dataBase.......");
    6         System.out.println("添加用户信息成功...");
    7     }
    8 }

    4、实现被代理对象的增强类:

     1 public class LogHandler implements InvocationHandler {
     2 
     3     private Object target;
     4 
     5     public LogHandler(Object target) {
     6         this.target = target;
     7     }
     8 
     9     @Override
    10     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    11         System.out.println("开始记录日志");
    12         method.invoke(target, args);
    13         System.out.println("日志记录完成");
    14         return null;
    15     }
    16 }

    5、调用测试: 

    1 public static void main(String[] args) {
    2     UserDao dao = new UserDaoImpl();
    3     LogHandler handler = new LogHandler(dao);
    4 
    5     UserDao proxy = (UserDao) Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(), handler);    
    6     proxy.addUser(user);
    7 }

    二、动态生成的代理文件查看: 

    1、在调用动态代理的main方法中加上:

    1 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

    2、利用ProxyGenerator生成:  

     1 public static void main(String[] args) {
     2         byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", UserDaoImpl.class.getInterfaces());
     3         String path = "E:\$Proxy0.class";
     4         try(FileOutputStream fos = new FileOutputStream(path)) {
     5             fos.write(classFile);
     6             fos.flush();
     7             System.out.println("代理类class文件写入成功");
     8         } catch (Exception e) {
     9             System.out.println("写文件错误");
    10         }
    11 }

    这样在运行代码的时候就会在项目的根目录(或者指定目录)下生成 com.sun.proxy.$ProxyX.class 了,反编译查看:

     1 public final class $Proxy0 extends Proxy implements UserDao {
     2     private static Method m1;
     3     private static Method m2;
     4     private static Method m3;
     5     private static Method m0;
     6 
     7     public $Proxy0(InvocationHandler var1) throws  {
     8         super(var1);
     9     }
    10 
    11     ......
    12 
    13     public final void addUser(User var1) throws  {
    14         try {
    15             super.h.invoke(this, m3, new Object[]{var1});
    16         } catch (RuntimeException | Error var3) {
    17             throw var3;
    18         } catch (Throwable var4) {
    19             throw new UndeclaredThrowableException(var4);
    20         }
    21     }
    22   
    23     static {
    24         try {
    25             m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
    26             m2 = Class.forName("java.lang.Object").getMethod("toString");
    27             m3 = Class.forName("com.ucar.test.service.UserDao").getMethod("addUser", Class.forName("com.ucar.test.dto.User"));
    28             m0 = Class.forName("java.lang.Object").getMethod("hashCode");
    29         } catch (NoSuchMethodException var2) {
    30             throw new NoSuchMethodError(var2.getMessage());
    31         } catch (ClassNotFoundException var3) {
    32             throw new NoClassDefFoundError(var3.getMessage());
    33         }
    34     }
    35 }

    可以看到: 

    1) 代理类$Proxy0Proxy派生而来,并且实现了UserDao接口;

    2) static块中生成了Object类的三个方法:toStringequalshashCode,并且也生成了UserDao接口的addUser方法;

    3) 调用端通过Proxy.newProxyInstance获取的对象实例也就是这个$Proxy0类型的对象,默认情况下这个类是不保存到磁盘上的,直接在内存中通过ClassLoader加载,因此在断点调试时是无法定位到这个类里面的;

    4) 当调用UserDao接口的addUser方法时,其实是调用InvocationHandler.invoke方法,InvocationHandler的实现也就是我们前面实现的LogHandler类,这样就将调用转到LogHandler.invoke方法;

    三、源码分析:

    1、首先从Proxy.newProxyInstance开始分析:

     1 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException{
     2         // null检查,h为null就抛出NullPointerException
     3         Objects.requireNonNull(h);
     4         // 将接口类对象数组clone一份。
     5         final Class<?>[] intfs = interfaces.clone();
     6         
     7         //执行权限检查
     8         final SecurityManager sm = System.getSecurityManager();
     9         if (sm != null) {
    10             checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    11         }
    12 
    13         /*
    14          * Look up or generate the designated proxy class.
    15          */
    16          // 查找或者是生成一个特定的代理类对象
    17         Class<?> cl = getProxyClass0(loader, intfs);
    18 
    19         /*
    20          * Invoke its constructor with the designated invocation handler.
    21          */
    22         try {
    23             if (sm != null) {
    24                 checkNewProxyPermission(Reflection.getCallerClass(), cl);
    25             }
    26             // 是static final 修饰的,源码: private static final Class<?>[] constructorParams ={ InvocationHandler.class };
    27             // 从代理类对象中查找参数为InvocationHandler的构造器
    28             final Constructor<?> cons = cl.getConstructor(constructorParams);
    29             final InvocationHandler ih = h;
    30             // 检测构造器是否是Public修饰,如果不是则强行转换为可以访问的。
    31             if (!Modifier.isPublic(cl.getModifiers())) {
    32                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
    33                     public Void run() {
    34                         cons.setAccessible(true);
    35                         return null;
    36                     }
    37                 });
    38             }
    39             // 通过反射,将h作为参数,实例化代理类,返回代理类实例。
    40             return cons.newInstance(new Object[]{h});
    41         } catch (IllegalAccessException|InstantiationException e) {
    42             throw new InternalError(e.toString(), e);
    43         } catch (InvocationTargetException e) {
    44             Throwable t = e.getCause();
    45             if (t instanceof RuntimeException) {
    46                 throw (RuntimeException) t;
    47             } else {
    48                 throw new InternalError(t.toString(), t);
    49             }
    50         } catch (NoSuchMethodException e) {
    51             throw new InternalError(e.toString(), e);
    52         }
    53 }

    这个方法主要工作: 

    1) getProxyClass0(loader, intfs)方法生成了上面的代理类$Proxy0,生成时主要根据intfs接口获取接口并生成,因此这就是JDK动态代理的类必须要定义接口的愿意;

    2) cons.newInstance(new Object[]{h})利用反射技术实例化代理类,并返回实例化对象;

    2、getProxyClass0方法:

     1 /**
     2      * 生成一个代理类对象,
     3      * Generate a proxy class.  Must call the checkProxyAccess method
     4      * to perform permission checks before calling this.
     5      */
     6     private static Class<?> getProxyClass0(ClassLoader loader,
     7                                            Class<?>... interfaces) {
     8         // 接口类对象数组不能大于65535个,否则抛出异常
     9         if (interfaces.length > 65535) {
    10             throw new IllegalArgumentException("interface limit exceeded");
    11         }
    12         // 从代理类对象缓存中,根据类加载器和接口类对象数组查找代理类对象,
    13         // If the proxy class defined by the given loader implementing
    14         // the given interfaces exists, this will simply return the cached copy;
    15         // otherwise, it will create the proxy class via the ProxyClassFactory
    16         return proxyClassCache.get(loader, interfaces);
    17     }

    在这个方法中,是直接从一个叫proxyClassCache缓存中读取的,来看一下这个缓存的声明:

    1 private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    看一下WeakCache类的大概结构:

     1 final class WeakCache<K, P, V> {
     2 
     3     private final ReferenceQueue<K> refQueue= new ReferenceQueue<>();
     4     // the key type is Object for supporting null key
     5     // key的类型为Object,支持null key,这里的null key并不是真的可以使用null最为key,而是一个new Objdec()对象实例。ConcurrentHashMap,不允许键或值null,而HashMap可以。ConcurrentHashMap是线程安全的,HashMap不是。
     6     private final ConcurrentMap<Supplier<V>, Boolean> reverseMap= new ConcurrentHashMap<>();
     7     
     8     private final BiFunction<K, P, ?> subKeyFactory;
     9     private final BiFunction<K, P, V> valueFactory;
    10 
    11     //构造方法
    12     public WeakCache(BiFunction<K, P, ?> subKeyFactory,
    13                      BiFunction<K, P, V> valueFactory) {
    14         this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
    15         this.valueFactory = Objects.requireNonNull(valueFactory);
    16     }
    17 
    18     
    19     public V get(K key, P parameter) {
    20        //下面会详细介绍这个方法
    21     }
    22 
    23   ......
    24 }

    3、WeakCache.get方法:

     1     // key是类加载器,parameter为接口类对象数组
     2     public V get(K key, P parameter) {
     3         // 接口类对象数组null检查。
     4         Objects.requireNonNull(parameter);
     5         
     6         // 删除过时的条目
     7         expungeStaleEntries();
     8         // 生成缓存key对象实例,如果key = null,cacheKey = new Object();
     9         Object cacheKey = CacheKey.valueOf(key, refQueue);
    10 
    11         // lazily install the 2nd level valuesMap for the particular cacheKey
    12         // 从缓存map中读取指定cacheKey的缓存数据valuesMap
    13         ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    14         
    15         if (valuesMap == null) {
    16             //如果valuesMap为null,则新增
    17             //putIfAbsent方法解释:如果值存在则返回值,并且不对原来的值做任何更改,如果不存在则新增,并返回null
    18             //Absent的意思是缺席,不在
    19             ConcurrentMap<Object, Supplier<V>> oldValuesMap= map.putIfAbsent(cacheKey,valuesMap = new ConcurrentHashMap<>());
    20             if (oldValuesMap != null) {
    21                 valuesMap = oldValuesMap;
    22             }
    23         }
    24 
    25         // create subKey and retrieve the possible Supplier<V> stored by that
    26         // subKey from valuesMap
    27         // 获取subKey,这里用到了上面提到的Proxy的静态内部类KeyFactory:subKeyFactory.apply(ket,parameter)
    28         Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    29         // 从valuesMap中获取supplier
    30         Supplier<V> supplier = valuesMap.get(subKey);
    31         Factory factory = null;
    32 
    33         while (true) {
    34             if (supplier != null) {
    35                 // supplier might be a Factory or a CacheValue<V> instance
    36                 // 4,从工厂中获取代理类对象
    37                 V value = supplier.get();
    38                 if (value != null) {
    39                     // 5,返回
    40                     return value;
    41                 }
    42             }
    43             // else no supplier in cache
    44             // or a supplier that returned null (could be a cleared CacheValue
    45             // or a Factory that wasn't successful in installing the CacheValue)
    46 
    47             // lazily construct a Factory
    48             if (factory == null) {
    49                 //1,实例化工厂
    50                 factory = new Factory(key, parameter, subKey, valuesMap);
    51             }
    52 
    53             if (supplier == null) {
    54                 //2,保存到valuesMap中
    55                 supplier = valuesMap.putIfAbsent(subKey, factory);
    56                 if (supplier == null) {
    57                     // successfully installed Factory
    58                     // 3,赋值
    59                     supplier = factory;
    60                 }
    61                 // else retry with winning supplier
    62             } else {
    63                 if (valuesMap.replace(subKey, supplier, factory)) {
    64                     // successfully replaced
    65                     // cleared CacheEntry / unsuccessful Factory
    66                     // with our Factory
    67                     supplier = factory;
    68                 } else {
    69                     // retry with current supplier
    70                     supplier = valuesMap.get(subKey);
    71                 }
    72             }
    73         }
    74     }

    其中supplier就是factory 

    4、Factory.get方法

     1 private final class Factory implements Supplier<V> {
     2 
     3         private final K key;
     4         private final P parameter;
     5         private final Object subKey;
     6         private final ConcurrentMap<Object, Supplier<V>> valuesMap;
     7 
     8         Factory(K key, P parameter, Object subKey,
     9                 ConcurrentMap<Object, Supplier<V>> valuesMap) {
    10             this.key = key;
    11             this.parameter = parameter;
    12             this.subKey = subKey;
    13             this.valuesMap = valuesMap;
    14         }
    15 
    16         @Override
    17         public synchronized V get() { // serialize access
    18             // re-check
    19             // 检查
    20             Supplier<V> supplier = valuesMap.get(subKey);
    21             if (supplier != this) {
    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 
    31             // create new value
    32             V value = null;
    33             try {
    34                 // valueFactory就是WeakCache的valueFactory属性,因为Factory是WeakCache的内部类,所以可以直接访问WeakCache的valueFactory属性
    35                 value = Objects.requireNonNull(valueFactory.apply(key, parameter));
    36             } finally {
    37                 if (value == null) { // remove us on failure
    38                     valuesMap.remove(subKey, this);
    39                 }
    40             }
    41             // the only path to reach here is with non-null value
    42             assert value != null;
    43 
    44             // wrap value with CacheValue (WeakReference)
    45             CacheValue<V> cacheValue = new CacheValue<>(value);
    46 
    47             // try replacing us with CacheValue (this should always succeed)
    48             if (valuesMap.replace(subKey, this, cacheValue)) {
    49                 // put also in reverseMap
    50                 reverseMap.put(cacheValue, Boolean.TRUE);
    51             } else {
    52                 throw new AssertionError("Should not reach here");
    53             }
    54 
    55             // successfully replaced us with new CacheValue -> return the value
    56             // wrapped by it
    57             return value;
    58         }
    59     }

    这里最关键的代码:valueFactory.apply(key, parameter)valueFactory就是Proxy的静态内部类ProxyClassFactory 

    5、ProxyClassFactory.apply方法

      1      /**
      2      * 一个利用给定的类加载器和接口类数组生成,定义并返回代理类对象的工厂方法
      3      * A factory function that generates, defines and returns the proxy class given
      4      * the ClassLoader and array of interfaces.
      5      */
      6     private static final class ProxyClassFactory
      7         implements BiFunction<ClassLoader, Class<?>[], Class<?>>
      8     {
      9         // prefix for all proxy class names
     10         // 所有代理类对象的前缀
     11         private static final String proxyClassNamePrefix = "$Proxy";
     12 
     13         // next number to use for generation of unique proxy class names
     14         // 用于生成唯一代理类名称的下一个数字
     15         private static final AtomicLong nextUniqueNumber = new AtomicLong();
     16 
     17         @Override
     18         public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
     19             
     20             Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
     21             // 
     22             for (Class<?> intf : interfaces) {
     23                 /*
     24                  * Verify that the class loader resolves the name of this
     25                  * interface to the same Class object.
     26                  */
     27                 Class<?> interfaceClass = null;
     28                 try {
     29                     // 加载接口类,获得接口类的类对象,第二个参数为false表示不进行实例化
     30                     interfaceClass = Class.forName(intf.getName(), false, loader);
     31                 } catch (ClassNotFoundException e) {
     32                 }
     33                 if (interfaceClass != intf) {
     34                     throw new IllegalArgumentException(
     35                         intf + " is not visible from class loader");
     36                 }
     37                 /*
     38                  * Verify that the Class object actually represents an
     39                  * interface.
     40                  */
     41                 if (!interfaceClass.isInterface()) {
     42                     throw new IllegalArgumentException(
     43                         interfaceClass.getName() + " is not an interface");
     44                 }
     45                 /*
     46                  * Verify that this interface is not a duplicate.
     47                  */
     48                 if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
     49                     throw new IllegalArgumentException(
     50                         "repeated interface: " + interfaceClass.getName());
     51                 }
     52             }
     53             // package to define proxy class in
     54             // 代理类的包名
     55             String proxyPkg = null;     
     56             int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
     57 
     58             /*
     59              * Record the package of a non-public proxy interface so that the
     60              * proxy class will be defined in the same package.  Verify that
     61              * all non-public proxy interfaces are in the same package.
     62              */ 
     63             for (Class<?> intf : interfaces) {
     64                 int flags = intf.getModifiers();
     65                 if (!Modifier.isPublic(flags)) {
     66                     accessFlags = Modifier.FINAL;
     67                     String name = intf.getName();
     68                     int n = name.lastIndexOf('.');
     69                     String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
     70                     if (proxyPkg == null) {
     71                         proxyPkg = pkg;
     72                     } else if (!pkg.equals(proxyPkg)) {
     73                         throw new IllegalArgumentException(
     74                             "non-public interfaces from different packages");
     75                     }
     76                 }
     77             }
     78 
     79             if (proxyPkg == null) {
     80                 // if no non-public proxy interfaces, use com.sun.proxy package
     81                 proxyPkg = com.sun.proxy package
     82                 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
     83             }
     84 
     85             /*
     86              * 生成代理类的类名
     87              * Choose a name for the proxy class to generate.
     88              */
     89             long num = nextUniqueNumber.getAndIncrement();
     90             String proxyName = proxyPkg + proxyClassNamePrefix + num;
     91 
     92             /*
     93              * Generate the specified proxy class.
     94              */
     95             //生成代理类class文件
     96             byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
     97             try {
     98                 // 返回代理类对象
     99                 return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
    100             } catch (ClassFormatError e) {
    101                 /*
    102                  * A ClassFormatError here means that (barring bugs in the
    103                  * proxy class generation code) there was some other
    104                  * invalid aspect of the arguments supplied to the proxy
    105                  * class creation (such as virtual machine limitations
    106                  * exceeded).
    107                  */
    108                 throw new IllegalArgumentException(e.toString());
    109             }
    110         }
    111     }
    112   }

    这里的ProxyGenerator.generateProxyClass生成了代理类的字节码文件

    6、ProxyGenerator.generateProxyClass方法:

     1 public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
     2     ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
     3    // 真正用来生成代理类字节码文件的方法在这里
     4     final byte[] var4 = var3.generateClassFile();
     5    // 保存代理类的字节码文件
     6     if(saveGeneratedFiles) {
     7         AccessController.doPrivileged(new PrivilegedAction() {
     8             public Void run() {
     9                 try {
    10                     int var1 = var0.lastIndexOf(46);
    11                     Path var2;
    12                     if(var1 > 0) {
    13                         Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar), 
    14                                                                                new String[0]);
    15                         Files.createDirectories(var3, new FileAttribute[0]);
    16                         var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
    17                     } else {
    18                         var2 = Paths.get(var0 + ".class", new String[0]);
    19                     }
    20 
    21                     Files.write(var2, var4, new OpenOption[0]);
    22                     return null;
    23                 } catch (IOException var4x) {
    24                     throw new InternalError("I/O exception saving generated file: " + var4x);
    25                 }
    26             }
    27         });
    28     }
    29 
    30     return var4;
    31 }

    其中generateClassFile是真正用于生成代理类字节码文件的方法;saveGeneratedFiles判断是否要将代理类字节码文件保存到本地磁盘文件,其定义为:

    1 private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));

     可以看到saveGeneratedFiles是从系统环境变量中读取的”sun.misc.ProxyGenerator.saveGeneratedFiles”变量并转换成布尔类型;

    7、generateClassFile方法:

      1 private byte[] generateClassFile() {
      2     //下面一系列的addProxyMethod方法是将接口中的方法和Object中的方法添加到代理方法中(proxyMethod)
      3     this.addProxyMethod(hashCodeMethod, Object.class);
      4     this.addProxyMethod(equalsMethod, Object.class);
      5     this.addProxyMethod(toStringMethod, Object.class);
      6     Class[] var1 = this.interfaces;
      7     int var2 = var1.length;
      8 
      9     int var3;
     10     Class var4;
     11    //获得接口中所有方法并添加到代理方法中
     12     for(var3 = 0; var3 < var2; ++var3) {
     13         var4 = var1[var3];
     14         Method[] var5 = var4.getMethods();
     15         int var6 = var5.length;
     16 
     17         for(int var7 = 0; var7 < var6; ++var7) {
     18             Method var8 = var5[var7];
     19             this.addProxyMethod(var8, var4);
     20         }
     21     }
     22 
     23     Iterator var11 = this.proxyMethods.values().iterator();
     24     //验证具有相同方法签名的方法的返回类型是否一致
     25     List var12;
     26     while(var11.hasNext()) {
     27         var12 = (List)var11.next();
     28         checkReturnTypes(var12);
     29     }
     30 
     31     //后面一系列的步骤用于写代理类Class文件
     32     Iterator var15;
     33     try {
     34          //生成代理类的构造函数
     35         this.methods.add(this.generateConstructor());
     36         var11 = this.proxyMethods.values().iterator();
     37 
     38         while(var11.hasNext()) {
     39             var12 = (List)var11.next();
     40             var15 = var12.iterator();
     41 
     42             while(var15.hasNext()) {
     43                 ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
     44                 //将代理类字段声明为Method,并且字段修饰符为 private static.
     45                //因为 10 是 ACC_PRIVATE和ACC_STATIC的与运算 故代理类的字段都是 private static Method ***
     46                 this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, 
     47                                "Ljava/lang/reflect/Method;", 10));
     48                //生成代理类的方法
     49                 this.methods.add(var16.generateMethod());
     50             }
     51         }
     52        //为代理类生成静态代码块对某些字段进行初始化
     53         this.methods.add(this.generateStaticInitializer());
     54     } catch (IOException var10) {
     55         throw new InternalError("unexpected I/O Exception", var10);
     56     }
     57 
     58     if(this.methods.size() > 'uffff') { //代理类中的方法数量超过65535就抛异常
     59         throw new IllegalArgumentException("method limit exceeded");
     60     } else if(this.fields.size() > 'uffff') {// 代理类中字段数量超过65535也抛异常
     61         throw new IllegalArgumentException("field limit exceeded");
     62     } else {
     63         // 后面是对文件进行处理的过程
     64         this.cp.getClass(dotToSlash(this.className));
     65         this.cp.getClass("java/lang/reflect/Proxy");
     66         var1 = this.interfaces;
     67         var2 = var1.length;
     68 
     69         for(var3 = 0; var3 < var2; ++var3) {
     70             var4 = var1[var3];
     71             this.cp.getClass(dotToSlash(var4.getName()));
     72         }
     73 
     74         this.cp.setReadOnly();
     75         ByteArrayOutputStream var13 = new ByteArrayOutputStream();
     76         DataOutputStream var14 = new DataOutputStream(var13);
     77 
     78         try {
     79             var14.writeInt(-889275714);
     80             var14.writeShort(0);
     81             var14.writeShort(49);
     82             this.cp.write(var14);
     83             var14.writeShort(this.accessFlags);
     84             var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
     85             var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
     86             var14.writeShort(this.interfaces.length);
     87             Class[] var17 = this.interfaces;
     88             int var18 = var17.length;
     89 
     90             for(int var19 = 0; var19 < var18; ++var19) {
     91                 Class var22 = var17[var19];
     92                 var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
     93             }
     94 
     95             var14.writeShort(this.fields.size());
     96             var15 = this.fields.iterator();
     97 
     98             while(var15.hasNext()) {
     99                 ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
    100                 var20.write(var14);
    101             }
    102 
    103             var14.writeShort(this.methods.size());
    104             var15 = this.methods.iterator();
    105 
    106             while(var15.hasNext()) {
    107                 ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
    108                 var21.write(var14);
    109             }
    110 
    111             var14.writeShort(0);
    112             return var13.toByteArray();
    113         } catch (IOException var9) {
    114             throw new InternalError("unexpected I/O Exception", var9);
    115         }
    116     }
    117 }

    其中addProxyMethod实现将接口与Object中一些方法添加到代理类中; 

    8、addProxyMethod 

     1 private void addProxyMethod(Method var1, Class<?> var2) {
     2     String var3 = var1.getName();//获得方法名称
     3     Class[] var4 = var1.getParameterTypes();//获得方法参数类型
     4     Class var5 = var1.getReturnType();//获得方法返回类型
     5     Class[] var6 = var1.getExceptionTypes();//异常类型
     6     String var7 = var3 + getParameterDescriptors(var4);//获得方法签名
     7     Object var8 = (List)this.proxyMethods.get(var7);//根据方法前面获得proxyMethod的value
     8     if(var8 != null) {//处理多个代理接口中方法重复的情况
     9         Iterator var9 = ((List)var8).iterator();
    10 
    11         while(var9.hasNext()) {
    12             ProxyGenerator.ProxyMethod var10 = (ProxyGenerator.ProxyMethod)var9.next();
    13             if(var5 == var10.returnType) {
    14                 ArrayList var11 = new ArrayList();
    15                 collectCompatibleTypes(var6, var10.exceptionTypes, var11);
    16                 collectCompatibleTypes(var10.exceptionTypes, var6, var11);
    17                 var10.exceptionTypes = new Class[var11.size()];
    18                 var10.exceptionTypes = (Class[])var11.toArray(var10.exceptionTypes);
    19                 return;
    20             }
    21         }
    22     } else {
    23         var8 = new ArrayList(3);
    24         this.proxyMethods.put(var7, var8);
    25     }
    26 
    27     ((List)var8).add(new ProxyGenerator.ProxyMethod(var3, var4, var5, var6, var2, null));
    28 }

    JDK动态代理的原理是根据定义好的规则,用传入的接口创建一个新类,JDK的动态代理只能代理接口中的方法,是针对接口生成代理类。这就是为什么采用动态代理时为什么只能用接口引用指向代理,而不能用传入的类引用执行动态类。

    四、参考资料:

    https://www.jianshu.com/p/471c80a7e831

    https://blog.csdn.net/u012834750/article/details/82499648

    https://www.cnblogs.com/zhangchengzi/p/9713807.html

  • 相关阅读:
    [BZOJ3671][UOJ#6][NOI2014]随机数生成器
    [BZOJ3670][UOJ#5][NOI2014]动物园
    [UOJ#131][BZOJ4199][NOI2015]品酒大会
    [BZOJ4530][Bjoi2014]大融合 LCT + 启发式合并
    有趣的题目名称,有趣的题目
    [BZOJ2959]长跑——新技能:LCT+缩圈
    贴一下WC总结里提到的那道裸题吧。。。
    System and method for assigning a message
    http请求
    jQuery 语法
  • 原文地址:https://www.cnblogs.com/laoxia/p/11121962.html
Copyright © 2011-2022 走看看