返回

Spring AOP 源码解析(下)

后端

深入解析 Spring AOP 源码(下)

在上一篇文章中,我们已经对 Spring AOP 的基本原理和使用方式有了初步的了解。在本文中,我们将继续深入探讨 Spring AOP 的源码,重点分析 Spring AOP 是如何根据不同的情况选择合适的代理方式,以及 Spring AOP 的代理工厂是如何创建代理对象的。

一、代理方式的选择

Spring AOP 在生成代理对象之前,需要先决定到底是使用 JDK 动态代理还是 CGLIB 动态代理。这取决于目标对象是否实现了接口。

1. JDK 动态代理

JDK 动态代理是通过实现 InvocationHandler 接口来创建代理对象的。当调用代理对象的方法时,实际调用的却是 InvocationHandler 接口的方法。InvocationHandler 接口只有一个方法:invoke()。在 invoke() 方法中,我们可以对方法调用进行拦截,并执行一些额外的操作。

JDK 动态代理的优点是简单易用,并且不需要修改目标对象的字节码。缺点是只能代理实现了接口的目标对象。

2. CGLIB 动态代理

CGLIB 动态代理是通过继承目标对象来创建代理对象的。当调用代理对象的方法时,实际调用的却是目标对象的方法。CGLIB 动态代理可以在运行时修改目标对象的字节码,因此可以代理任何目标对象,无论它是否实现了接口。

CGLIB 动态代理的优点是可以代理任何目标对象。缺点是需要修改目标对象的字节码,并且性能开销比 JDK 动态代理稍大。

3. Spring AOP 如何选择代理方式

Spring AOP 在选择代理方式时,会根据以下规则进行判断:

  • 如果目标对象实现了接口,则使用 JDK 动态代理。
  • 如果目标对象没有实现接口,则使用 CGLIB 动态代理。

二、代理工厂

代理工厂是 Spring AOP 创建代理对象的核心组件。它负责根据目标对象和通知创建代理对象。

代理工厂的实现类是 ProxyFactory。ProxyFactory 类提供了一系列方法来创建代理对象,包括:

  • setInterfaces():设置代理对象要实现的接口。
  • setTarget():设置代理对象的目标对象。
  • addAdvice():添加通知到代理对象。
  • getProxy():创建代理对象。

代理工厂在创建代理对象时,会根据目标对象和通知的类型来决定是使用 JDK 动态代理还是 CGLIB 动态代理。

1. JDK 动态代理

如果目标对象实现了接口,代理工厂会使用 JDK 动态代理来创建代理对象。具体步骤如下:

  • 创建一个 InvocationHandler 对象。
  • 使用 Proxy 类创建代理对象,并指定 InvocationHandler 对象。

2. CGLIB 动态代理

如果目标对象没有实现接口,代理工厂会使用 CGLIB 动态代理来创建代理对象。具体步骤如下:

  • 创建一个 CGLIB 子类。
  • 使用 Enhancer 类创建代理对象,并指定 CGLIB 子类。

三、织入

织入是将通知应用到目标对象的过程。Spring AOP 的织入分为两种方式:

1. 编译时织入

编译时织入是在编译阶段将通知织入到目标对象中。这种方式需要修改目标对象的字节码。Spring AOP 不支持编译时织入。

2. 运行时织入

运行时织入是在运行阶段将通知织入到目标对象中。这种方式不需要修改目标对象的字节码。Spring AOP 支持运行时织入。

Spring AOP 的运行时织入是通过代理对象来实现的。当调用代理对象的方法时,实际调用的却是目标对象的方法。在目标对象的方法执行前后,代理对象会执行相应的通知。

四、总结

Spring AOP 是一个强大的面向切面编程框架。它允许您在不修改源代码的情况下向现有代码添加功能。Spring AOP 的实现原理是基于动态代理技术。Spring AOP 根据目标对象和通知的类型来选择合适的代理方式,并通过代理工厂来创建代理对象。Spring AOP 的织入方式是运行时织入,它是通过代理对象来实现的。

希望本文能帮助您更好地理解 Spring AOP 的工作原理。