我在我的Kotlin-Gradle多模块项目中使用io.freefair.aspectj.post-compile-weaving插件在我的SprringBoot应用程序中启用方面.

当我try 在一个简单的项目中使用这个插件时,它工作得非常好,当我将项目拆分成一个多模块的项目时,它开始不再识别方面

这是我在GitHub上创建的MCVE.

因此,我基本上设置了根项目Gradle文件:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version "3.1.5"
    id("io.spring.dependency-management") version "1.1.3"
    id("io.freefair.aspectj.post-compile-weaving") version "6.6.3"
    kotlin("jvm") version "1.8.22"
    kotlin("plugin.spring") version "1.8.22"
}

group = "com.voiddev"

allprojects {
    apply(plugin = "org.jetbrains.kotlin.jvm")
    apply(plugin = "kotlin-spring")
    apply(plugin = "io.spring.dependency-management")
    apply(plugin = "org.springframework.boot")
    apply(plugin = "io.freefair.aspectj.post-compile-weaving")

    version = "0.0.1-SNAPSHOT"
    java {
        sourceCompatibility = JavaVersion.VERSION_17
    }

    repositories {
        mavenCentral()
    }

    dependencies {
        implementation("org.springframework.boot:spring-boot-starter-web")
        implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
        implementation("org.jetbrains.kotlin:kotlin-reflect")
        testImplementation("org.springframework.boot:spring-boot-starter-test")

        implementation("org.aspectj:aspectjrt:1.9.19")
    }

    tasks.withType<KotlinCompile> {
        kotlinOptions {
            freeCompilerArgs += "-Xjsr305=strict"
            jvmTarget = "17"
        }
    }

    tasks.withType<Test> {
        useJUnitPlatform()
    }
}

然后,我所要做的就是try 使用‘公共’模块中定义的方面,在‘服务器’模块中. 我确实正确地导入了服务器模块中的公共模块,因为我能够访问common模块中定义的类. 这是我的服务器Gradle文件:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version "3.1.5"
    id("io.spring.dependency-management") version "1.1.3"
    id("io.freefair.aspectj.post-compile-weaving") version "6.6.3"
    kotlin("jvm") version "1.8.22"
    kotlin("plugin.spring") version "1.8.22"
}

group = "com.voiddev"

dependencies {
    implementation(project(":common"))
}

tasks {
    bootJar {
        archiveBaseName.set(rootProject.name)
    }
}

然而,这些方面被简单地忽略了

推荐答案

实际上,我想知道您为什么要使用本机AspectJ,因为您将方面应用于Spring服务.也就是说,Spring附带的称为Spring AOP的常规"AOP lite"就足够了.为此,您不需要任何Extra构建插件.

无论如何,回答您的问题:您的模块common是一个方面库.要使AspectJ编译器识别它,您应该将它放在aspectpath上,而不是放在常规的类路径上.在作为documented here的Free Fair中,这是这样做的:

dependencies {
  aspect(project(":common"))
}

然后,它就起作用了.鉴于此服务器应用程序,...

@SpringBootApplication
class ServerApplication

fun main(args: Array<String>) {
  runApplication<ServerApplication>(*args).use {
    println(it.getBean(AspectService::class.java).randomFunction())
  }
}

...控制台日志(log)将为:

MetricAspect: $Proxy57
MetricAspect: $Proxy57
Hello Aspect

但当然,在使用本机AspectJ时,您的切入点过于通用.它将匹配两次,一次为call,一次为execution个连接点.这在Spring AOP中不会发生,因为后者只知道execution.您可以这样修复它:

@After("@annotation(metricAnnotation) && execution(* *(..))")

控制台日志(log)更改为:

MetricAspect: $Proxy57
Hello Aspect

您可能还希望有 Select 地考虑将两个模块中的FreeFair插件从6.6.3升级到8.4:

id("io.freefair.aspectj.post-compile-weaving") version "8.4"

Kotlin相关问答推荐

在kotlin中使用List(mylist. size){index—TODO()}或Map迭代>

我可以检测一个函数是否在Kotlin中被递归调用(即,重入)吗?

从 Kotlin 的父类获取函数注解

Java/Kotlin中类似Rust般的注释编译?

Criteria Api 中的 Kotlin 泛型

为什么会出现Kotlin.Unit错误以及如何修复它?

Kotlin SIZE_BYTES

Kotlin:调用 CoroutineScope.launch 与在协程内启动之间的区别

Kotlin 如何使用其 get 函数在内部检索映射值

kotlin 父类具有依赖于抽象变量的变量

在子类中覆盖 kotlin 运算符扩展函数

我们应该在 Effect 和 Either 之间 Select 哪个作为我们业务服务的返回类型?

为 Gradle 子项目配置 Kotlin 扩展

我什么时候可以在 LazyList 或 Column 的范围内使用 Composable?

Kotlin 日期格式从一种更改为另一种

T except one class

如果我可以将 Flow 和 StateFlow 与生命周期范围 \ viewLifecycleOwner.lifecycleScope 一起使用,那么在 ViewModel 中使用 LiveData 有什么意义

如何将vararg转换为list?

Kotlin:使用Gradle进行增量编译

从 Kotlin 访问 Integer.class