前言
AOP 代理主要分为静态代理和动态代理,静态代理的代表为 AspectJ,而动态代理则以 Spring AOP 为代表。静态代理是编译期实现,动态代理是运行期实现,静态代理拥有相对更好的性能。
静态代理在编译阶段生成 AOP 代理类,生成的字节码就织入了增强后的 AOP 对象。动态代理则不会修改字节码,而是在内存中临时生成一个 AOP 对象,这个 AOP 对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
Spring AOP 中的动态代理
Spring AOP 中存在两种代理实现机制,分别是 JDK 动态代理和 CGLib 动态代理。
Spring 中虽然使用了与 AspectJ 一样的注解,没有使用 AspectJ 的编译器 ,采用的仍是 Spring AOP 动态代理,而是 AspectJ 静态代理。
Spring 在选择用 JDK 还是 CGLib 的依据:
- 当 Bean 实现接口时,Spring 就会用 JDK 的动态代理。
- 当 Bean 没有实现接口时则使用 CGlib实现。
注:从 Spring Boot 2.0 开始,默认的 AOP 策略已经更换为 CGLIB,即 proxy-target-class = true。
JDK 动态代理
JDK 动态代理使用步骤
定义 InvocationHandler 类并实现 InvocationHandler 接口。
通过 Proxy.newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h) 方法生成动态代理类实例。
通过生成的动态代理类实例调用目标方法,目标方法的调用会被转发给 InvocationHandler 类中的 invoke() 方法处理。
JDK 动态代理源码分析
JDK 动态代理通过反射创建 Class 并动态生成类字节码加载到 JVM 中,并且要求被代理的类必须实现一个接口,核心是 InvocationHandler 接口和 Proxy 类。
1 | public interface InvocationHandler { |
Proxy 类则是用来创建一个代理对象的类,先来看看生成代理对象的 newProxyInstance() 方法,这个方法接收接受以下三个参数:
- ClassLoader loader:定义由哪个 Classloader 对象负责加载生成的代理对象。
- Class<?>[] interfacess:接口数组,表示提供给代理对象的一组接口,代理类可以调用接口数组中实现的所有方法。
- InvocationHandler h:表面当代理对象调用方法的时候会关联到哪一个 InvocationHandler 对象上,并最终由其调用。
通过 Proxy.newProxyInstance() 方法创建的代理对象是在 JVM 运行时动态生成的一个对象。