jdk动态代理源码分析

Jdk的动态代理是在方法调用期间来动态生成代理的字节码类,而后进行方法调用,好比自己方法是save()方法,而后实际调用save方法的时候不会直接调用save方法,而是先去调用一个代理方法save,而后经过代理方法去调用代理监控类的invoke方法,而后咱们就能够在invoke方法中再去调用实际的save方法,而且能够定制个性化的需求.缓存

jdk提供了如何实现动态代理的方法,有几个要求,app

1.创建一个代理的监控类这个类必须实现InvocationHandler接口,重写他的invoke方法,在invoke方法中进行个性化定制和实际方法的调用函数

2.要想被代理,那被代理对象必须实现接口,jdk动态代理是基于接口来代理的,因此实现类中本身特点的方法是没办法使用jdk动态代理加强的工具

3.jdk提供了一个工具类来生成代理对象Proxy,提供了一个静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)来帮忙快速建立代理类,代理

参数1:被代理类加载的时候用的类加载器(用来加载动态建立的代理类的字节码)对象

参数2:被代理类实现的全部接口,要给动态建立的代理类的字节码实现这些接口,而且做为标识能够判断是否已经缓存过实现这些接口的代理类避免重复建立接口

参数3:自定义的代理的监控类,会做为构造函数的参数,赋值给新建立的代理类字节码生成对象的成员变量InvocationHandler h;v8

 

大体理解下逻辑,Proxy类调用newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)get

1.首先根据传进来的类加载器,全部的接口[参数1,参数2]来获得最终的代理对象的Class对象,在这里会实现传进来的接口中的全部方法[Look up or generate the designated proxy class.]io

 

2.而后获取代理对象的Class的的构造方法,而且是带有一个参数类型是{ InvocationHandler.class }的构造方法Constructor对象

而后调用Constructor的newInstance(new Object[] { h });方法建立出代理对象类型为Object类型

3.而后在初始化代理对象时候经过静态代码块中反射的方式Class.forName("xxx").getMethod("save", new Class[0])把真实的方法获取到,做为成员变量保存

 

4.而后调用代理对象中实现了接口的方法save,在save方法中调用成员变量InvocationHandler h的invoke方法,这样就进入了咱们自定义的代理类的监控类[实现了InvocationHandler接口]中实现的invoke方法

 

5.至此整个执行流程结束,完成了代理方法的调用,在代理方法中调用个性化的方法而且也调用了被代理对象的方法自己

 

示例以下:

Jdk1.6中的实现

核心方法就是如何建立的代理对象,调用的是Proxy类的静态方法newInstance方法,实现以下:

其中的重点是如何根据类加载器,实现的接口获得代理对象的Class对象,实现方法在getProxyClass(loader, interfaces)中,具体以下:

上面建立代理类的Class中核心方法是ProxyGenerator.generateProxyClass(proxyName, interfaces);具体的实现能够点进去看,实际又去调用了ProxyGenerator.generateClassFile()方法,并且有一个成员属性能够设置是否把生成的代理类字节码保存到硬盘上属性名为saveGeneratedFiles,设置方式以下:

能够看下生成的class,而后反编译以后

反编译以后以下:

上面就是一个对象被代理的整个过程了.

 

大体理解下逻辑,Proxy类调用newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)

1.首先根据传进来的类加载器,全部的接口[参数1,参数2]来获得最终的代理对象的Class对象,在这里会实现传进来的接口中的全部方法[Look up or generate the designated proxy class.]

 

2.而后获取代理对象的Class的的构造方法,而且是带有一个参数类型是{ InvocationHandler.class }的构造方法Constructor对象

而后调用Constructor的newInstance(new Object[] { h });方法建立出代理对象类型为Object类型

3.而后在初始化代理对象时候经过静态代码块中反射的方式Class.forName("xxx").getMethod("save", new Class[0])把真实的方法获取到,做为成员变量保存

 

4.而后调用代理对象中实现了接口的方法save,在save方法中调用成员变量InvocationHandler h的invoke方法,这样就进入了咱们自定义的代理类的监控类[实现了InvocationHandler接口]中实现的invoke方法

 

5.至此整个执行流程结束,完成了代理方法的调用,在代理方法中调用个性化的方法而且也调用了被代理对象的方法自己

Spring中的具体的jdk基于接口方式的动态代理的监控类是JdkDynamicAopProxy,他里边确定实现了invoke方法,而且实现了InvocationHandler接口,而且提供了getProxy方法,

Jdk1.7中的实现

1.7中一样的核心入口方法也是Proxy.newInstance(),实现以下

上面的重点是如何获取代理对象的Class对象,在jdk1.6中的方法名是getProxyClass(loader,interfaces),1.7中进行了封装在getProxyClass0(loader, intfs)中,具体实现以下:

上面的缓存是proxyClassCache,定义的是一个WeakCache类型的对象,以下:

map是实现缓存的核心变量,是一个嵌套结构(key,sub-key) -> value   key是传入的ClassLoader包装后的对象,sub-key是WeakCache构造函数传入的的KeyFactory()生成的,value就是生成的代理类对象是由WeakCache传入的构造函数ProxyClassFactory生成的,生成sub-key的KeyFactory以下:

Value是传入的ProxyClassFactory生成的,对应的apply方法其实就是jdk1.6中的getProxyClass方法,以下:

经过sub-key拿到一个Supplier<Class<?>>对象,而后调用get方法获得代理类的Class对象,而后看proxyClassCache.get(loader,interfaces)方法以下:

经过sub-key获得supplier,supplier就是这个factory调用他的get方法以下:

1.7没有1.6的逻辑好理顺,可是思路都是同样的,缓存中获取,有了就返回,没有就建立.

相关文章
相关标签/搜索