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 编织方面,您有两个选择:
- 保留
io.freefair.aspectj
插件一步编译编织方面:将您的方面实现为 .java
或 .aj
以便它可以由 ajc 编译
- 切换到
io.freefair.aspectj.post-compile-weaving
插件,以便将编译和编织步骤分开:在这种情况下,您可以将 Aspect 实现保留为 Kotlin,但您必须将其放在 src/main/kotlin
中。然后你的 Aspect 将由 kotlinc 编译,然后由 ajc 编织。
我有一个 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 编织方面,您有两个选择:
- 保留
io.freefair.aspectj
插件一步编译编织方面:将您的方面实现为.java
或.aj
以便它可以由 ajc 编译
- 切换到
io.freefair.aspectj.post-compile-weaving
插件,以便将编译和编织步骤分开:在这种情况下,您可以将 Aspect 实现保留为 Kotlin,但您必须将其放在src/main/kotlin
中。然后你的 Aspect 将由 kotlinc 编译,然后由 ajc 编织。