You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java与Kotlin混合使用时AspectJ织入失效问题求助

Kotlin+Java混合项目AspectJ切点无法匹配Java类的解决方案

问题场景

项目采用AspectJ、Kotlin与Java混合开发,切面需拦截Java类Class1的sayHello()方法,但AspectJ在compileKotlin阶段执行织入时,compileJava任务尚未执行,导致AspectJ无法找到目标Java类,出现如下警告:

Task :compileKotlin

2 warnings
cc\nostaldaisuki\aspectjtest\AspectJTest.kt [warning] no match for this type name: cc.nostaldaisuki.aspectjtest.Class1 [Xlint:invalidAbsoluteTypeName]

G:\Codes\JVM\aspectj-test\build\classes\kotlin\main!cc\nostaldaisuki\aspectjtest\AspectJTest.class [warning] advice defined in cc.nostaldaisuki.aspectjtest.AspectJTest has not been applied [Xlint:adviceDidNotMatch]

Task :compileJava

将Class1改为Kotlin类后,织入可正常执行,现需解决Java与Kotlin混合场景下的该问题。

项目配置与代码

build.gradle.kts配置

plugins {
    kotlin("jvm") version "1.9.0"
    kotlin("kapt") version "1.9.22"
    id("io.freefair.aspectj.post-compile-weaving") version "8.4"
    id("java")
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.aspectj:aspectjrt:1.9.8.RC3")
    implementation("org.aspectj:aspectjweaver:1.9.8.RC3")
}

kotlin {
    jvmToolchain(17)
}

应用入口代码

package cc.nostaldaisuki.aspectjtest

fun main() {
    val class1Instance = Class1("Hello!")
    class1Instance.sayHello()
}

切面类代码

package cc.nostaldaisuki.aspectjtest

import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect

@Aspect
class AspectJTest {
    @Around("execution(* cc.nostaldaisuki.aspectjtest.Class1.sayHello())")
    fun replaceSayHello(joinPoint: ProceedingJoinPoint) {
        val targetObject = joinPoint.target as Class1Kt
        val field = targetObject.javaClass.getDeclaredField("content")
        field.isAccessible = true
        val fieldContent = field.get(targetObject) as String
        Class2.replacement(fieldContent)
    }
}

解决方案

方案1:调整编译任务顺序,让Java先编译

Gradle默认先执行compileKotlin再执行compileJava,修改任务依赖,让Java类先编译完成,确保Kotlin切面能访问到编译后的Java类:

tasks.compileKotlin {
    // 让Kotlin编译依赖Java编译完成
    dependsOn(tasks.compileJava)
    // 给Kotlin编译器添加Java编译输出目录到类路径
    classpath += files(tasks.compileJava.get().destinationDirectory)
}

tasks.compileJava {
    // 解除Java编译对Kotlin编译的默认依赖,避免循环依赖
    dependsOn.remove(tasks.compileKotlin)
}

注意:此方案要求Kotlin代码不依赖未编译的Java代码,若Kotlin存在对Java类的编译期依赖,需确保依赖关系合理。

方案2:将切面改为Java类

将Kotlin切面改为Java类,这样切面会在compileJava阶段编译,AspectJ在后续织入时可直接访问已编译的Java目标类:

package cc.nostaldaisuki.aspectjtest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import java.lang.reflect.Field;

@Aspect
public class AspectJTest {
    @Around("execution(* cc.nostaldaisuki.aspectjtest.Class1.sayHello())")
    public void replaceSayHello(ProceedingJoinPoint joinPoint) throws Throwable {
        Object targetObject = joinPoint.getTarget();
        Field field = targetObject.getClass().getDeclaredField("content");
        field.setAccessible(true);
        String fieldContent = (String) field.get(targetObject);
        Class2.replacement(fieldContent);
    }
}

此方案无需调整任务顺序,兼容性更强,适合大多数混合开发场景。

方案3:调整AspectJ织入时机

配置Freefair的AspectJ插件,让织入操作在所有编译任务(Kotlin+Java)完成后执行:

tasks.named<io.freefair.gradle.plugins.aspectj.tasks.AspectJWeave>("weaveMain") {
    // 确保织入任务在Kotlin和Java编译完成后执行
    dependsOn(tasks.compileKotlin, tasks.compileJava)
    // 添加Kotlin和Java的编译输出目录到织入类路径
    classpath += files(tasks.compileKotlin.get().destinationDirectory, tasks.compileJava.get().destinationDirectory)
}

此方案通过延迟织入时机,确保所有目标类都已编译完成,适合需要保留Kotlin切面的场景。

内容的提问来源于stack exchange,提问作者Nostal Yuu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 19:45:25