Spring Boot - 在同一项目中编译时编织和 Spring AOP/运行时编织(代理)

问题描述 投票:0回答:2

如果有代码在同一项目中同时使用带有运行时编织/代理使用的 Spring AOP 和编译时编织,Spring Boot 会做什么。例如,假设您有一个如下所示的方面:

@Aspect
@Component
public class TestAspect {
  // ...
}

@Component 的存在意味着我们正在使用 Spring AOP 和代理,并且你的 pom.xml 中有这个

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>aspectj-maven-plugin</artifactId>
  <version>1.11</version>
  <executions>
    <execution>
      <goals>
        <goal>compile</goal>       <!-- use this goal to weave all your main classes -->
        <goal>test-compile</goal>  <!-- use this goal to weave all your test classes -->
      </goals>
    </execution>
  </executions>
</plugin>

这意味着我们正在使用编译时编织。

哪一个优先?是使用编译时编织还是代理?

java spring aop aspectj spring-aop
2个回答
3
投票

嗯,你为什么不尝试一下呢?那不是比问更快吗?好的,这是我的想法:

  • AspectJ 完全独立于 Spring AOP 或一般的 Spring。您可以在没有 Spring 的情况下使用它,也可以在 Spring 应用程序中使用它,通常是通过加载时编织 (LTW)。 Spring 手册解释了如何配置它。
  • 如果您使用 LTW,Spring 会意识到它,要么是因为您通过 Spring 选项显式配置它,要么只是因为 Spring 以某种方式检测到活动的编织代理。无论哪种方式,一旦 LTW 处于活动状态,Spring 就会停用其自己的 Spring AOP。
  • 关于编译时编织(CTW),Spring 不知道它,因为它发生在构建时,甚至在 Spring 启动之前。根据您使用的 AspectJ 功能类型,AspectJ 增强类可能看起来与常规 Java 类没有什么不同,例如用于简单的 ITD 字段或方法定义。然而,在大多数情况下,修改使得您需要类路径上的 AspectJ 运行时库
    aspectjrt.jar
    。如果是这种情况,无论有没有 Spring,应用程序都应该正常运行。
  • 对于 Spring,我不希望它首先注意到您之前使用过 CTW 的任何信息。因此,它不会停用 Spring AOP。您应该能够将两者结合使用。只需确保不要将您的本机方面声明为 Spring 组件,否则 Spring AOP 会尝试重新应用它。结果将是不可预测的。但是普通的 Spring AOP 方面组件应该可以正常工作。当然,您还需要确保 AspectJ Maven 不会意外地将您的 Spring AOP 方面编译和编织为本机方面。您可以通过将 AspectJ 方面放入另一个模块、创建方面库,然后通过
    <aspectLibraries>
    配置在 AspectJ Maven 中引用它来实现这一点。

底线:您不能混合使用 Spring AOP 和 AspectJ LTW,但您应该能够使用 Spring AOP + AspectJ CTW。您应该有充分的理由这样做并了解自己在做什么。


0
投票

我最近遇到了一种情况,当 AspectJ (P)CTW 启动时,Spring AOP 似乎被禁用,但不是应用程序明智的,而是类明智的。在 Spring 代码中进行一些调试后,我发现上述观察结果是有条件的

在我们的例子中,我们使用

aspectOf()
将ajc切面注册为bean,以便切面也可以注入spring bean依赖项。这使得 Spring 可以看到这些方面。

Spring AOP 将所有

@Aspect
bean 注册为
Advisor
,并在创建代理 bean 时在创建 bean 时查找它。 (代理bean,因此在创建时,已经确定了合格的方面)

测试 Advisor 是否有资格使用目标 bean 时,

AspectJExpressionPointcut.matches(Class<?> targetClass)
在调用堆栈中被调用(可能仅适用于
InstantiationModelAwarePointcutAdvisorImpl
左右)。 并且aspectOf()创建的方面的相关顾问在这一行测试失败
(this.aspectCompiledByAjc && compiledByAjc(targetClass))
前者是正确的,因为我们使用了
aspectOf()
,后者实际上使用一些临时逻辑检查类定义是否有 ajc 编译的迹象。

总而言之,具有

Advisor
类型
AspectJExpressionPointcut
ClassFilter
不能应用于已经 ajc 编织的类 (
@Transactional
的顾问使用
TransactionAttributeSourcePointcut
并且不检查ajc编译是否发生,因此基于spring代理的@Transactional甚至可以在ajc编译的类上工作)

© www.soinside.com 2019 - 2024. All rights reserved.