Skip to content

编程式创建 @AspectJ 代理 (Programmatic Creation of @AspectJ Proxies)

除了通过使用 <aop:config><aop:aspectj-autoproxy> 在配置中声明切面外,还可以通过编程方式创建为目标对象提供通知的代理。关于 Spring AOP API 的详细细节,请参阅下一章。在这里,我们重点介绍使用 @AspectJ 切面自动创建代理的能力。

你可以使用 org.springframework.aop.aspectj.annotation.AspectJProxyFactory 类为一个或多个 @AspectJ 切面通知的目标对象创建代理。该类的基本用法非常简单,如下例所示:

java
// 创建一个可以为给定目标对象生成代理的工厂
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);

// 添加一个切面,该类必须是一个 @AspectJ 切面
// 你可以根据需要多次调用此方法来添加不同的切面
factory.addAspect(SecurityManager.class);

// 你也可以添加现有的切面实例,所提供的对象类型必须是一个 @AspectJ 切面
factory.addAspect(usageTracker);

// 现在获取代理对象...
MyInterfaceType proxy = factory.getProxy();
kotlin
// 创建一个可以为给定目标对象生成代理的工厂
val factory = AspectJProxyFactory(targetObject)

// 添加一个切面,该类必须是一个 @AspectJ 切面
// 你可以根据需要多次调用此方法来添加不同的切面
factory.addAspect(SecurityManager::class.java)

// 你也可以添加现有的切面实例,所提供的对象类型必须是一个 @AspectJ 切面
factory.addAspect(usageTracker)

// 现在获取代理对象...
val proxy = factory.getProxy<Any>()

更多信息请参见 javadoc


补充教学

1. 为什么需要编程式创建代理?

在大多数 Spring 应用中,我们依赖容器自动处理 AOP。但在以下场景中,AspectJProxyFactory 非常有用:

  • 单元测试:如果你只想测试某个切面逻辑(例如权限检查或日志)是否能正确拦截方法,而不想启动庞大的 Spring 容器,可以用编程式方式快速构建测试环境。
  • 构建轻量级工具库:如果你在编写一个不依赖完整 Spring 容器的独立 Java/Kotlin 工具库,但又想利用 AOP 带来的解耦优势。
  • 极端动态的场景:当切面的逻辑或拦截的目标在运行时才能确定,且无法通过静态配置来表达时。

2. ProxyFactory vs AspectJProxyFactory

  • ProxyFactory:是 Spring AOP 的基础工厂类。它要求你手动传入 AdviceAdvisorInterceptor。它本身不理解 @Aspect@Before 等注解。
  • AspectJProxyFactory:是 ProxyFactory 的子类。它专门为 @AspectJ 注解风格设计。它能解析你传入的切面类,自动将其中的注解转化为 Spring 内部的 Advisor,大大降低了手动构造的复杂度。

3. 注意点:它不具备“自动发现”能力

使用 AspectJProxyFactory 时,你必须显式调用 addAspect 方法。 它不会像 Spring 容器那样去扫描路径下的 @Aspect 类。这意味着你需要手动管理切面的生命周期和实例化。

4. 性能考量

虽然手动创建代理在运行时的性能与容器创建的代理无异,但在高频创建代理对象的场景下,由于每次都需要解析注解,会有一定的初始化开销。 建议:如果某些代理对象需要被频繁创建,考虑缓存生成的工厂实例或代理类。

5. 关于 TargetObject

即便你传入的是一个原始对象,返回的 proxy 依然是一个由 Spring AOP 构建的代理(JDK 动态代理或 CGLIB 代理)。这回到了我们之前讨论的代理机制——要注意“自调用”问题依然存在。

Based on Spring Framework.