Spring 使用 Kotlin 和 Gradle 的 AOP (AspectJ) - 我无法让它工作

Spring AOP (AspectJ) with Kotlin and Gradle - I can't get it to work

我有一个 Spring Boot + Kotlin + Gradle 项目。我想为我的用例创建一个小型库。这个库应该使用 AOP 来消除我观察到的一些横切问题。

因此我开始将这两个依赖项添加到我的 gradle 构建文件中。

build.gradle.kts

implementation("org.springframework:spring-aop:5.2.9.RELEASE")
implementation("org.springframework:spring-aspects:5.2.9.RELEASE")

由于互联网上的一些建议,我还添加了 freefair aspectj 插件。 根据此文档,我创建的以下方面应放在 src/main/aspectj 中:https://docs.freefair.io/gradle-plugins/5.2.1/reference/#_io_freefair_aspectj

This plugin adds AspectJ support to the project, by adding a aspectj directory to every source set. Source contained in the src/main/aspectj directory will be compiled with ajc by the compileAspectj task.

plugins {
    // ...
    id("io.freefair.aspectj") version "5.2.1"
    // ...
}

然后我开始创建我的第一个方面,它匹配每个用 @Foozy

注释的方法

src/main/aspectj/FoozyAspect.kt < 'special' 源路径

@Component
@Aspect
class FoozyAspect {

    @Before("@annotation(com.client.annotation.Foozy)")
    fun doStuff() {
        LOG.info("Do Stuff")
    }

    companion object {
        private val LOG = LoggerFactory.getLogger(FoozyAspect::class.java)
    }
}

然后我创建了这个注解

src/main/kotlin/com.client.annotation/Foozy.kt

@Target(AnnotationTarget.FUNCTION)
annotation class Foozy

现在为了测试是否一切正常,我创建了一个单元测试

src/test/kotlin/FoozyAspectTest.kt

@SpringBootTest
@EnableAspectJAutoProxy
internal class FoozyAspectTest {
    private val testCandidate: TestCandidate = TestCandidate()

    @Test
    fun `should work with aspect`() {
        testCandidate.doStuff()
    }
}

src/test/TestCandidate.kt

class TestCandidate {
    @Foozy
    fun doStuff(): String {
        return "stuff"
    }
}

结果

在调试模式下执行文本不会产生等待的信息日志 Do Stuff,也不会在 FoozyAspect.kt doStuff()[= 中的断点处停止线程56=] 方法。 我不知道在这里配置什么。 出于充分的理由,我有点怀疑我正在混淆不同的“方式”来让它工作,或者只是错过了 preconfiguration/prerequisites.

中的一些最后步骤

这看起来像是经典 Spring AOP 问题的第 347 次重复:如果您阅读手册,您会注意到 Spring AOP 仅适用于 Spring 组件,例如通过 @Component@Bean.

声明

你的TestCandidate好像是个POJO,所以Spring不知道。此外,如果您将其作为一个组件,请确保您从容器中获取一个实例,而不是仅通过测试中的构造函数调用创建一个实例。

AspectJ 编译器无法编译 Kotlin 源代码。 src/main/aspectj 中的 .kt 文件将被完全忽略。

根据您真正想做的事情,您有不同的选择:

您希望 Aspect 在编译时由 ajc 编织,还是只想使用“普通”Spring AOP?

差异解释如下:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-choosing

如果您只想使用 Spring AOP,则不需要特殊的 gradle 插件。只需将您的 .kt 文件放入 src/main/kotlin 并遵循 Spring AOP 文档。

如果您想在编译时使用 ajc 编织方面,您有两个选择:

  1. 保留 io.freefair.aspectj 插件一步编译编织方面:将您的方面实现为 .java.aj 以便它可以由 ajc
  2. 编译
  3. 切换到 io.freefair.aspectj.post-compile-weaving 插件,以便将编译和编织步骤分开:在这种情况下,您可以将 Aspect 实现保留为 Kotlin,但您必须将其放在 src/main/kotlin 中。然后你的 Aspect 将由 kotlinc 编译,然后由 ajc 编织。