Spring AOP使用了两种代理机制: 一种是基于JDK的动态代理; 一种是基于 CGLib 的动态代理.
JDK本身只提供接口代理, 而不支持类的代理.
JDK动态代理主要涉及 java.lang.reflect 包中的两个类: Proxy 和 InvocationHandler.
InvocationHandler 是一个接口, 可以通过实现该接口定义横切逻辑, 并通过反射机制调用目标类中的代码, 动态地将横切逻辑和业务逻辑编织在一起. Proxy利用 InvocationHandler 动态创建一个符合某一接口的的实例, 生成目标类的代理对象.
一. JDK动态代理的使用
使用 InvocationHandler 将业务逻辑代码与横切逻辑代码编织到一起
invoke() 方法将横切逻辑代码与业务逻辑代码编织到一起, 可以将 InvocationHandler 看成编织器.
实现 InvocationHandler 接口, 实现了一个 invoke() 方法. invoke(Object proxy,Method method,Object[] args). proxy是最终生成的代理实例; method 是被代理目标实例的某个具体方法; args 是被代理目标实例某个方法的具体入参, 在方法反射调用时使用. 在构造函数中, target 是希望被代理的目标对象.
通过 Proxy 创建接口的代理实例
通过 Proxy 的 newProxyInstance() 静态方法为编织了业务逻辑和监视逻辑的 handler 创建一个符合 Interface 接口的代理实例.
该方法的第一个参数为类加载器, 第二个参数为创建代理实例所需实现的一组接口, 第三个参数为整合了业务逻辑和横切逻辑的编织器对象.
二. JDK动态代理的原理
我们使用代理类 Proxy 创建了一个代理实例, 这个代理实例执行接口中的方法实际上是执行了 InvocationHandler接口 实现类中的 invoke() 方法中自定义编织到一块的横切逻辑和业务逻辑代码. 我们查看一下 Proxy 类的源码, 简单概述以下代理实例的创建过程.
1. newProxyInstance 方法
2.着重看一下 getProxyClass0() 方法.
proxyClassCache 代理缓存实际上使用了 WeakCache 缓存类来实现的.
3.如果根据提供的类加载器和接口数组在缓存中能找到代理类就直接返回该代理类, 否则调用 ProxyClassFactory 去生成代理类.
先不用关注缓存机制, 着重看下 ProxyClassFactory 是如何生成代理类的.
4. 来看一下 ProxyGenerator.generateProxyClass() 是如何生成代理类的字节码文件的
5.我们可以读取Proxy 生成的字节码文件, 通过反编译, 将Class文件输出
可以得到代理类,代码如下:
代理类继承了 Proxy 类, 实现了代理的接口, 由于Java不能多继承, 这里已经继承了 Proxy 类, 不能再继承其他类了, 所以JDK动态代理不支持对实现类的代理, 只支持对接口的代理.
提供一个 InvocationHandler 作为构造方法的入参.
生成静态代码块初始化接口中的方法. JDK动态代理除了代理接口中的方法, 还代理了Object 类中的 equals(), toString(), hashCode() 方法.
代理类调用接口中的方法, 实际是调用了 InvocationHandler 中的 invoke() 方法. 从而实现了对接口的代理.