前言
对于使用过 Spring 的朋友, 应该都使用过 AOP, 那么今天我们来对 AOP 的原理: 动态代理 来一探究竟.
静态代理
在动态代理之前, 我们先来看看静态代理, 看下其实现方式及其优缺点.
静态代理的原理是委托类和代理类都实现同一个接口, 代理类中会调用委托类的方法, 同时代理类中可以加一些自己的逻辑.
公共接口
1 | public interface IService { |
委托类
1 | public class RealService implements IService { |
代理类
1 | public class ProxyService implements IService { |
测试
1 | public class Main { |
输出:
before...
hello
after...
可以看到委托类和代理类都实现了同一个接口, 然后代理类在初始化时, 传入委托类对象, 然后在代理类自己的
sayHello()
方法中, 即调用了委托类的sayHello()
方法, 还加了自己的逻辑, 输出了before
和after
.
但这种方式有着明显的缺点:
- 必须要继承一个接口
- 必须要手工创建对应的代理类
- 硬编码, 当接口需要改动或代理类较多时不宜维护.
动态代理
JDK 动态代理
公共接口
1 | public interface IService { |
委托类
1 | public class RealService implements IService { |
代理类
1 | import java.lang.reflect.InvocationHandler; |
测试
1 | import java.lang.reflect.Proxy; |
代码看起来好像更复杂了一些, 我们可以看到 IService
和 RealService
的定义不变, 但创建代理类的方式变化了, 它使用 java.lang.reflect.Proxy
的静态方法 newProxyInstance
来创建代理类.
1 | public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) |
它有三个参数:
loader
表示类加载器.interfaces
表示代理类要实现的接口列表, 元素的类型只能是接口.h
就是上面我们定义的SimpleInvocationHandler
它实现了InvocationHandler
接口, 并复写了invoke
方法, 对代理接口的所有方法调用都会转到此方法上.
newProxyInstance
的返回值是 Object
, 可以强制转化为 interfaces
数组中的任意接口类型, 但不能转化为某个普通类型, 如 RealService
. 即使它代理的实际对象是 RealService
.
接着我们在来看看 SimpleInvocationHandler
, 它实现了 InvocationHandler
接口, 它通过构造方法传入被代理对象 realObject
. 复写的 invoke
方法有三个参数:
proxy
表示代理对象本身, 需要注意, 它不是被代理的对象.method
表示正在被调用的方法args
表示方法的参数
需要注意这句代码:
1 | Object result = method.invoke(realObject, args); |
我们来反编译看下, 它为我们动态生成的代理类:
1 | package com.sun.proxy; |
可以看到, 其实也就是生成了一个类, 实现了我们传入的接口, 它所有方法都是调用的 SimpleInvocationHandler
的 invoke 方法.
相比于静态代理, 这里的动态代理看起来麻烦了不少, 但它却更加通用. 我们不用为每个被代理的类都创建一个静态代理类, 而是当代理类要做的功能不变时, 只需要有这一个代理类即可. 说起来可能有些不好理解, 看代码吧:
1 | public class GeneralProxyDemo { |
在这里有两个接口 ServiceA
和 ServiceB
, 他们对应的实现类为 ServiceAImpl
和 ServiceBImpl
. 虽然他们的接口和实现类完全不同, 但通过动态代理. 他们都可以使用 SimpleInvocationHandler
中 invoke
中的代理逻辑.
CGLIB 动态代理
上面讲到的 JDK 动态代理, 有一定的局限性, 那就是只能为接口创建代理, 返回的对象也只能是接口类型的, 如果一个类没有接口, 或者想代理非接口中定义的方法, JDK 动态代理就无法实现了. 这里就要用到 CGLIB
动态代理了.
1 | import net.sf.cglib.proxy.Enhancer; |
RealService
表示被代理的类, 它没有实现任何接口. getProxy()
方法为一个类生成代理对象, 这个代理对象可以转换为被代理类的类型, 它使用了 cglib
的 Enhancer
类, Enhancer
类的 setSuperclass
设置被代理的类, setCallback
设置被代理类的方法被调用时的处理类, Enhancer
支持多种类型, 这里使用的类实现了 MethodInterceptor
接口, 它与 JDK 动态代理中的 InvocationHandler
有点类似, 方法名称变成了intercept, 多了一个MethodProxy类型的参数.
与前面的 InvocationHandler
不同,SimpleInterceptor
中没有被代理的对象,它通过 MethodProxy
的 invokeSuper
方法调用被代理类的方法:
1 | Object result = proxy.invokeSuper(object, args); |
注意,它不能这样调用被代理类的方法:
1 | Object result = method.invoke(object, args); |
object 是代理对象,不能自己代理自己,会造成死循环。
基本的使用就这些, 先消化下, 自己动手实现, 后续我会更新一些 JDK 更细节上的内容.