博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
拆轮子系列--java动态代理源码分析
阅读量:7042 次
发布时间:2019-06-28

本文共 14103 字,大约阅读时间需要 47 分钟。

0.前言

代理模式是常见的设计模式,一般分为普通代理模式和动态代理模式,区别就在于代理类一个是自己写的,一个是动态生成的。无论是静态代理模式还是动态代理模式,其实结构都是相同的,看看UML类图。

(UML类图在编码设计的时候有很大作用,有时间写篇文章) 通过UML类图可以很清晰的看到代理类Proxy和被代理类RealSubject都实现了Subject接口,同时Proxy持有了RealSubject对象。通过代理类,我们就可以在被代理类的方法执行前和执行后执行一些我们需要的东西。动态代理就是这个Proxy是动态生成的。

1.动态代理用法

//Demoimport java.util.*;import java.lang.reflect.*;public class ProxyTest{   public static void main(String[] args)   {   	    System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");        Bat bat=new Bat();        FlyableInvocationHandler handler=new FlyableInvocationHandler(bat);        Flyable flyable= (Flyable) Proxy.newProxyInstance(Flyable.class.getClassLoader(),new Class
[]{Flyable.class},handler); flyable.fly(); }}interface Flyable{ void fly();}class Bat implements Flyable{ @Override public void fly() { System.out.println("fly in dark night"); }}class FlyableInvocationHandler implements InvocationHandler{ private Flyable flyable; public FlyableInvocationHandler(Flyable flyable) { this.flyable = flyable; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("展翅"); Object result = method.invoke(flyable, args); System.out.println("收翅"); return result; }}复制代码

这是一个动态代理的基本用法,通过调用Proxy.newProxyInstance生成一个代理类,这个代理类如何生成的,接着就看一下Proxy.newProxyInstance这个方法

@CallerSensitive    public static Object newProxyInstance(ClassLoader loader,                                          Class
[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class
[] intfs = interfaces.clone(); // Android-changed: sm is always null // final SecurityManager sm = System.getSecurityManager(); // if (sm != null) { // 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 { // Android-changed: sm is always null // if (sm != null) { // checkNewProxyPermission(Reflection.getCallerClass(), cl); // } final Constructor
cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { // Android-changed: Removed AccessController.doPrivileged cons.setAccessible(true); } 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); } }复制代码

首先生成代理类的Class对象

/*         * Look up or generate the designated proxy class.         */        Class
cl = getProxyClass0(loader, intfs);复制代码

关于这个Class对象是如何生的,我们待会儿再说。接着往下看。

final Constructor
cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { // Android-changed: Removed AccessController.doPrivileged cons.setAccessible(true); } return cons.newInstance(new Object[]{h});复制代码

通过代理类的class对象,找到其中参数类型为constructorParams的构造函数,这个constructorParams又是是什么

private static final Class
[] constructorParams = { InvocationHandler.class };复制代码

可以看到这是一个只包含InvocationHandler.class的Class数组。到这里我们就可以推测出,生成的代理类的某个构造函数是要传入InvocationHandler对象的,而这个InvocationHandler对象就是我们在调用Proxy.newInstance()方法时传入的,对应Demo里的FlyableInvocationHandler。之后就是调用该构造函数传入InvocationHandler参数构造一个对象并返回。

2.代理类的生成

上面说了,代理类的Class对象是由

Class
cl = getProxyClass0(loader, intfs);复制代码

生成的。那么接着看看这个getProxyClass0方法

private static Class
getProxyClass0(ClassLoader loader, Class
... interfaces) { 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); }复制代码

首先是一个65535的判断,如果接口数组的大小超过65535,就会报错,至于为什么是65535,不太清楚, 接着就是调用这个方法proxyClassCache.get(loader, interfaces)返回class对象,这个proxyClassCache是Proxy的一个成员变量

private static final WeakCache
[], Class
> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());复制代码

这里你可以理解为代理类的缓存,我们重点关注的就是ProxyClassFactory这个类,从名字也可以看出,这就是我们要找的生成代理类Class对象的地方。

/**     * A factory function that generates, defines and returns the proxy class given     * the ClassLoader and array of interfaces.     */    private static final class ProxyClassFactory        implements BiFunction
[], Class
> { // prefix for all proxy class names private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class
apply(ClassLoader loader, Class
[] interfaces) { Map
, 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 the default package. proxyPkg = ""; } { // Android-changed: Generate the proxy directly instead of calling // through to ProxyGenerator. List
methods = getMethods(interfaces); Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE); validateReturnTypes(methods); List
[]> exceptions = deduplicateAndGetExceptions(methods); Method[] methodsArray = methods.toArray(new Method[methods.size()]); Class
[][] exceptionsArray = exceptions.toArray(new Class
[exceptions.size()][]); /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; return generateProxy(proxyName, interfaces, loader, methodsArray, exceptionsArray); } } }复制代码

接下来分析一下这个方法

Map
, 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()); } }复制代码

这段代码就是用来生验证类加载器是否解析了此名称接口到同一个Class对象。其中有一行代码

if (!interfaceClass.isInterface()) {                    throw new IllegalArgumentException(                        interfaceClass.getName() + " is not an interface");                }复制代码

判断Class对象是否是接口类型,这就要求我们调用Proxy.newInstance方法时传入的Class<?>[] interfaces是接口的class对象。 剩下的代码使用来获得代理类的包名,代理类的名称以及代理类的Method数组,就不再细说了。最终调用

generateProxy(proxyName, interfaces, loader, methodsArray,                                     exceptionsArray);复制代码

生成代理类的Class对象,这个方法是一个native方法,就不进去再看了,分析到这里也差不多了。

3.代理类字节码

想要输出动态代理生成的字节码文件默认是不输出的,想输出到存储空间调用

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");复制代码

反编译字节码

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;final class $Proxy0  extends Proxy  implements Flyable{  private static Method m1;  private static Method m3;  private static Method m2;  private static Method m0;    public $Proxy0(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 localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }    public final void fly()  {    try    {      this.h.invoke(this, m3, null);      return;    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }    public final String toString()  {    try    {      return (String)this.h.invoke(this, m2, null);    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }    public final int hashCode()  {    try    {      return ((Integer)this.h.invoke(this, m0, null)).intValue();    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }    static  {    try    {      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });      m3 = Class.forName("Flyable").getMethod("fly", 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 localNoSuchMethodException)    {      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());    }    catch (ClassNotFoundException localClassNotFoundException)    {      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());    }  }}复制代码

和我们设想的一样,代理类持有了InvocationHandler对象,同时实现了传入的Interface接口,可以看到fly方法里调用了InvocationHandler的invoke方法,传入了this指针,方法method和参数null。

4.应用

至此动态代理基本上就分析完了,动态代理最常见的用处可能就是AOP编程了,在不改变已有类的情况下生成代理添加新的逻辑,有兴趣的可以看一下AOP编程。

关注我的公众号

转载地址:http://qaxal.baihongyu.com/

你可能感兴趣的文章
《Spark大数据分析:核心概念、技术及实践》一2.3 一个单独的Scala应用程序
查看>>
Phalcon入门教程之模型
查看>>
K近邻算法-KNN
查看>>
北京这两天为啥颜值爆表?
查看>>
HybridDB · 最佳实践 · HybridDB 数据合并的方法与原理
查看>>
《Unity着色器和屏幕特效开发秘笈(原书第2版)》一2.2 漫反射着色
查看>>
利用Fork/Join框架来统计某个字符串在某个文件夹的文件中出现的次数
查看>>
使用ownCloud在Linux安装你的个人云服务
查看>>
《深入实践Spring Boot》一1.6 小结
查看>>
XTTS,又一个值得你重视的Oracle数据库迁移升级利器
查看>>
error: src refspec master does not match any. error: failed to push some refs to
查看>>
《C语言及程序设计》实践项目——用break和continue改变流程
查看>>
Nodejs进阶:基于express+multer的文件上传
查看>>
利用ROS搭建应用基础套件
查看>>
MySQL · 物理备份 · Percona XtraBackup 备份原理
查看>>
The total number of locks exceeds the lock table size错误(已纠正)
查看>>
Java千百问_05面向对象(005)_接口和抽象类有什么区别
查看>>
c++虚函数表探究
查看>>
java自定义注解
查看>>
Zend的Registry机制
查看>>