java动态代理源码解析

2021-06-22 02:03

阅读:370

标签:record   rgs   oid   play   fun   tst   via   lis   div   

众所周知,java动态代理同反射原理一直是许多框架的底层实现,之前一直没有时间来分析动态代理的底层源码,现结合源码分析一下动态代理的底层实现

类和接口

java动态代理的主要类和接口有:java.lang.reflect.Proxy、java.lang.reflect.InvocationHandler

1 java.lang.reflect.Proxy:动态代理机制的主类,提供一组静态方法为一组接口动态的生成对象和代理类。

1、public static InvocationHandler getInvocationHandler(Object var0) -> 该方法用于获取指定代理对象所关联的调用处理器

2、public static Class> getProxyClass(ClassLoader var0, Class... var1) -> 该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象

3、public static Object newProxyInstance(ClassLoader var0, Class>[] var1, InvocationHandler var2) ->方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例

 

2  java.lang.reflect.InvocationHandler:调用处理器接口,自定义invoke方法,用于实现对于真正委托类的代理访问

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

3  java.lang.ClassLoader:类装载器类

 将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy类与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。

 demo

技术分享图片技术分享图片
public interface HelloService {
    void sayHello();
}
定义接口
技术分享图片技术分享图片
public class HelloServiceImpl implements HelloService{
    @Override
    public void sayHello() {
        System.out.println("hello 张三");
    }
}
接口实现
技术分享图片技术分享图片
public class HelloServiceProxy implements InvocationHandler{
    private Object target;

    public Object bind(Object target, Class[] interfaces) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result;
        System.out.println("###########这里是动态代理##########");
        //反射方法前调用
        System.out.println("调用前");
        //反射执行方法  相当于调用target.sayHelllo;
        result = method.invoke(target,args);
        //反射方法后调用.
        System.out.println("调用后");

        return result;
    }
}
生成代理类
技术分享图片技术分享图片
public class ProxyTest {

    public static void main(String[] args) {
        HelloServiceProxy proxy = new HelloServiceProxy();
        HelloService service = new HelloServiceImpl();
        HelloService serviceProxy = (HelloService)proxy.bind(service, new Class[] {HelloService.class});

        serviceProxy.sayHello();
    }
}
测试类

运行结果:

技术分享图片

 源码分析:

1 Proxy类的静态方法newProxyInstance方法

技术分享图片技术分享图片
    public static Object newProxyInstance(ClassLoader loader,
                                          Class>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        //验证传入的InvocationHandler是否为空
        Objects.requireNonNull(h);
        
        //克隆代理类实现的接口
        final Class>[] intfs = interfaces.clone();
        //获得安全管理器
        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 {
            //权限校验
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            //获取参数类型是InvocationHandler.class的代理类构造器
            final Constructor> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            //如果代理类是不可访问的, 就使用特权将它的构造器设置为可访问
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //传入InvocationHandler实例去构造一个代理类的实例,所有代理类都继承自Proxy,而Proxy构造方法需要InvocationHandler实例作为参数
            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

  从newProxyInstance方法看出,产生代理类核心代码在getProxyClass0

2 Proxy类的静态方法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 
 7         // If the proxy class defined by the given loader implementing
 8         // the given interfaces exists, this will simply return the cached copy;
 9         // otherwise, it will create the proxy class via the ProxyClassFactory
10         //如果由实现给定接口的代理类存在,这将简单地返回缓存的副本;否则,将通过ProxyClassFactory创建代理类
11         return proxyClassCache.get(loader, interfaces);
12     }
getProxyClass0

getProxyClass0通过类加载器和接口集合去缓存里面获取,如果能找到代理类就直接返回,否则就会调用ProxyClassFactory这个工厂去生成一个代理类,下面我们看下Proxy的静态内部类ProxyClassFactory

3 ProxyClassFactory

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

ProxyClassFactory中生成代理类核心代码 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);下面我们继续分析ProxyGenerator.generateProxyClass

4 ProxyGenerator.generateProxyClass

技术分享图片技术分享图片
 1 public static byte[] generateProxyClass(final String var0, Class>[] var1, int var2) {
 2         //构造ProxyGenerator对象
 3         ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
 4         //核心代码,生成代理类字节码文件
 5         final byte[] var4 = var3.generateClassFile();
 6         //如果需要保存生成的字节码文件,则将字节码文件写入磁盘
 7         if(saveGeneratedFiles) {
 8             AccessController.doPrivileged(new PrivilegedAction() {
 9                 public Void run() {
10                     try {
11                         int var1 = var0.lastIndexOf(46);
12                         Path var2;
13                         //生成存储路径
14                         if(var1 > 0) {
15                             Path var3 = Paths.get(var0.substring(0, var1).replace(‘.‘, File.separatorChar), new String[0]);
16                             Files.createDirectories(var3, new FileAttribute[0]);
17                             var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
18                         } else {
19                             var2 = Paths.get(var0 + ".class", new String[0]);
20                         }
21                         //将字节码文件写入磁盘
22                         Files.write(var2, var4, new OpenOption[0]);
23                         return null;
24                     } catch (IOException var4x) {
25                         throw new InternalError("I/O exception saving generated file: " + var4x);
26                     }
27                 }
28             });
29         }
30         //返回字节码文件
31         return var4;
32     }
generateProxyClass

ProxyGenerator.generateClassFile

跟踪了这么久源码,大boss终于出现了,下面我们分析ProxyGenerator.generateClassFile方法

技术分享图片技术分享图片
  1     private byte[] generateClassFile() {
  2         //1、将所有的方法组装成ProxyMethod对象
  3         //首先为代理类生成toString, hashCode, equals等代理方法
  4         this.addProxyMethod(hashCodeMethod, Object.class);
  5         this.addProxyMethod(equalsMethod, Object.class);
  6         this.addProxyMethod(toStringMethod, Object.class);
  7         Class[] var1 = this.interfaces;
  8         int var2 = var1.length;
  9 
 10         int var3;
 11         Class var4;
 12         //遍历每一个接口的每一个方法, 并生成ProxyMethod对象
 13         for(var3 = 0; var3 var3) {
 14             var4 = var1[var3];
 15             Method[] var5 = var4.getMethods();
 16             int var6 = var5.length;
 17 
 18             for(int var7 = 0; var7 var7) {
 19                 Method var8 = var5[var7];
 20                 this.addProxyMethod(var8, var4);
 21             }
 22         }
 23 
 24         Iterator var11 = this.proxyMethods.values().iterator();
 25 
 26         List var12;
 27         while(var11.hasNext()) {
 28             var12 = (List)var11.next();
 29             checkReturnTypes(var12);
 30         }
 31 
 32         //2、组装要生成的class文件的所有的字段信息和方法信息
 33         Iterator var15;
 34         try {
 35             //添加构造器方法
 36             this.methods.add(this.generateConstructor());
 37             var11 = this.proxyMethods.values().iterator();
 38 
 39             //遍历缓存中的代理方法
 40             while(var11.hasNext()) {
 41                 var12 = (List)var11.next();
 42                 var15 = var12.iterator();
 43 
 44                 while(var15.hasNext()) {
 45                     ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
 46                     //添加代理类的静态字段, 例如:private static Method m1;
 47                     this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
 48                     //添加代理类的代理方法
 49                     this.methods.add(var16.generateMethod());
 50                 }
 51             }
 52 
 53             //添加代理类的静态字段初始化方法
 54             this.methods.add(this.generateStaticInitializer());
 55         } catch (IOException var10) {
 56             throw new InternalError("unexpected I/O Exception", var10);
 57         }
 58 
 59         if(this.methods.size() > ‘\uffff‘) {
 60             throw new IllegalArgumentException("method limit exceeded");
 61         } else if(this.fields.size() > ‘\uffff‘) {
 62             throw new IllegalArgumentException("field limit exceeded");
 63         } else {
 64             //3、写入最终的class文件
 65             //验证常量池中存在代理类的全限定名
 66             this.cp.getClass(dotToSlash(this.className));
 67             //验证常量池中存在代理类父类的全限定名
 68             this.cp.getClass("java/lang/reflect/Proxy");
 69             var1 = this.interfaces;
 70             var2 = var1.length;
 71 
 72             //验证常量池存在代理类接口的全限定名
 73             for(var3 = 0; var3 var3) {
 74                 var4 = var1[var3];
 75                 this.cp.getClass(dotToSlash(var4.getName()));
 76             }
 77 
 78             //接下来要开始写入文件了,设置常量池只读
 79             this.cp.setReadOnly();
 80             ByteArrayOutputStream var13 = new ByteArrayOutputStream();
 81             DataOutputStream var14 = new DataOutputStream(var13);
 82 
 83             try {
 84                 //1.写入魔数
 85                 var14.writeInt(-889275714);
 86                 //2.写入次版本号
 87                 var14.writeShort(0);
 88                 //3.写入主版本号
 89                 var14.writeShort(49);
 90                 //4.写入常量池
 91                 this.cp.write(var14);
 92                 //5.写入访问修饰符
 93                 var14.writeShort(this.accessFlags);
 94                 //6.写入类索引
 95                 var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
 96                 //7.写入父类索引, 生成的代理类都继承自Proxy
 97                 var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
 98                 //8.写入接口计数值
 99                 var14.writeShort(this.interfaces.length);
100                 
101                 Class[] var17 = this.interfaces;
102                 int var18 = var17.length;
103 
104                 //9.写入接口集合
105                 for(int var19 = 0; var19 var19) {
106                     Class var22 = var17[var19];
107                     var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
108                 }
109                 //10.写入字段计数值
110                 var14.writeShort(this.fields.size());
111                 var15 = this.fields.iterator();
112                 //11.写入字段集合 
113                 while(var15.hasNext()) {
114                     ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
115                     var20.write(var14);
116                 }
117                 //12.写入方法计数值
118                 var14.writeShort(this.methods.size());
119                 var15 = this.methods.iterator();
120                 //13.写入方法集合
121                 while(var15.hasNext()) {
122                     ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
123                     var21.write(var14);
124                 }
125                  //14.写入属性计数值, 代理类class文件没有属性所以为0
126                 var14.writeShort(0);
127                 //转换成二进制数组输出
128                 return var13.toByteArray();
129             } catch (IOException var9) {
130                 throw new InternalError("unexpected I/O Exception", var9);
131             }
132         }
133     }
generateClassFile

动态代理的本质:通过类加载器获取类字节码,通过类实现的接口反射获得该类的属性,方法等,并生成新的字节码文件

6 代理类字节码文件分析 $Proxy0.class

技术分享图片技术分享图片
  1 package com.sun.proxy;
  2 
  3 import com.doubibi.framework.util.proxy.HelloService;
  4 import java.lang.reflect.InvocationHandler;
  5 import java.lang.reflect.Method;
  6 import java.lang.reflect.Proxy;
  7 import java.lang.reflect.UndeclaredThrowableException;
  8 
  9 public final class $Proxy0 extends Proxy
 10   implements HelloService
 11 {
 12   //equals方法
 13   private static Method m1;
 14   //HelloService 的sayHello方法
 15   private static Method m3;
 16   //toString方法
 17   private static Method m2;
 18   //hashCode方法
 19   private static Method m0;
 20 
 21   //构造方法
 22   public $Proxy0(InvocationHandler paramInvocationHandler)
 23     throws 
 24   {
 25     super(paramInvocationHandler);
 26   }
 27 
 28   public final boolean equals(Object paramObject)
 29     throws 
 30   {
 31     try
 32     {
 33       return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
 34     }
 35     catch (Error|RuntimeException localError)
 36     {
 37       throw localError;
 38     }
 39     catch (Throwable localThrowable)
 40     {
 41       throw new UndeclaredThrowableException(localThrowable);
 42     }
 43   }
 44 
 45   //调用了invocationHandler的invoke方法,invoke执行了HelloService 的sayHello方法
 46   public final void sayHello()
 47     throws 
 48   {
 49     try
 50     {
 51       this.h.invoke(this, m3, null);
 52       return;
 53     }
 54     catch (Error|RuntimeException localError)
 55     {
 56       throw localError;
 57     }
 58     catch (Throwable localThrowable)
 59     {
 60       throw new UndeclaredThrowableException(localThrowable);
 61     }
 62   }
 63 
 64   public final String toString()
 65     throws 
 66   {
 67     try
 68     {
 69       return (String)this.h.invoke(this, m2, null);
 70     }
 71     catch (Error|RuntimeException localError)
 72     {
 73       throw localError;
 74     }
 75     catch (Throwable localThrowable)
 76     {
 77       throw new UndeclaredThrowableException(localThrowable);
 78     }
 79   }
 80 
 81   public final int hashCode()
 82     throws 
 83   {
 84     try
 85     {
 86       return ((Integer)this.h.invoke(this, m0, null)).intValue();
 87     }
 88     catch (Error|RuntimeException localError)
 89     {
 90       throw localError;
 91     }
 92     catch (Throwable localThrowable)
 93     {
 94       throw new UndeclaredThrowableException(localThrowable);
 95     }
 96   }
 97 
 98   static
 99   {
100     try
101     {
102       m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
103       m3 = Class.forName("com.doubibi.framework.util.proxy.HelloService").getMethod("sayHello", new Class[0]);
104       m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
105       m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
106       return;
107     }
108     catch (NoSuchMethodException localNoSuchMethodException)
109     {
110       throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
111     }
112     catch (ClassNotFoundException localClassNotFoundException)
113     {
114       throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
115     }
116   }
117 }
$Proxy0

代理类$Proxy0调用了invocationHandler也就是的helloServiceProxy的invoke方法,而invoke通过反射执行了HelloService 的sayHello方法也就是HelloServiceImpl的sayHello方法。

自此java动态代理源码分析完成,笔者对动态代理理解更加深刻,如有不当之处还请各位读者指正

java动态代理源码解析

标签:record   rgs   oid   play   fun   tst   via   lis   div   

原文地址:https://www.cnblogs.com/allenli263/p/9621750.html


评论


亲,登录后才可以留言!