Spring 引导 - 在同一项目中编译时间编织和 Spring AOP/run 时间编织(代理)
Spring Boot - Compile time weaving and Spring AOP/run time weaving (proxies) in same project
如果有代码同时使用 Spring AOP 和 运行 时间 weaving/use 代理和编译时间编织,
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>
这意味着我们正在使用编译时编织。
哪个优先?是编译时编织使用,还是代理?
嗯,你为什么不试试呢?那不是比询问更快吗?好的,这是我的想法:
- AspectJ 通常完全独立于 Spring AOP 或 Spring。您可以在没有 Spring 的情况下使用它,也可以在 Spring 应用程序中使用它,通常是通过加载时织入 (LTW)。 Spring 手册解释了如何配置它。
- 如果你使用 LTW,Spring 会知道它,要么是因为你通过 Spring 选项明确配置它,要么只是因为 Spring 以某种方式检测到活动编织代理。无论哪种方式,只要 LTW 处于活动状态,Spring 就会停用其自己的 Spring AOP。
- 关于编译时编织 (CTW),Spring 不知道,因为它发生在构建期间,甚至在 Spring 开始之前。根据您使用的 AspectJ 功能类型,AspectJ 增强的 类 可能看起来与常规 Java 类 没有什么不同,例如用于简单的 ITD 字段或方法定义。然而,在大多数情况下,修改是这样的,您需要类路径上的 AspectJ 运行time 库
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。你应该有充分的理由这样做并理解你在做什么。
如果有代码同时使用 Spring AOP 和 运行 时间 weaving/use 代理和编译时间编织,
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>
这意味着我们正在使用编译时编织。
哪个优先?是编译时编织使用,还是代理?
嗯,你为什么不试试呢?那不是比询问更快吗?好的,这是我的想法:
- AspectJ 通常完全独立于 Spring AOP 或 Spring。您可以在没有 Spring 的情况下使用它,也可以在 Spring 应用程序中使用它,通常是通过加载时织入 (LTW)。 Spring 手册解释了如何配置它。
- 如果你使用 LTW,Spring 会知道它,要么是因为你通过 Spring 选项明确配置它,要么只是因为 Spring 以某种方式检测到活动编织代理。无论哪种方式,只要 LTW 处于活动状态,Spring 就会停用其自己的 Spring AOP。
- 关于编译时编织 (CTW),Spring 不知道,因为它发生在构建期间,甚至在 Spring 开始之前。根据您使用的 AspectJ 功能类型,AspectJ 增强的 类 可能看起来与常规 Java 类 没有什么不同,例如用于简单的 ITD 字段或方法定义。然而,在大多数情况下,修改是这样的,您需要类路径上的 AspectJ 运行time 库
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。你应该有充分的理由这样做并理解你在做什么。