如何在Gradle多模块项目中使用Groovy Abstract Syntax Tree(AST)
Gradle多模块项目中Groovy AST注解生效的完整实现方案
一、项目结构规划
先搭建清晰的多模块结构,把AST转换逻辑和业务代码分离:
root-project/ ├── ast-transform/ # AST转换模块(注解定义+转换逻辑) │ ├── src/main/groovy/ │ │ ├── com/example/ast/MyASTTransformation.groovy │ │ └── com/example/annotations/MyAnnotation.groovy │ ├── src/main/resources/ │ │ └── META-INF/services/org.codehaus.groovy.transform.ASTTransformation │ └── build.gradle ├── app-module/ # 业务模块(使用自定义注解) │ ├── src/main/groovy/ │ │ └── com/example/app/MyService.groovy │ └── build.gradle └── settings.gradle
二、AST转换模块配置与实现
1. 模块构建脚本(ast-transform/build.gradle)
配置Groovy和Java库插件,确保依赖和资源文件正确打包:
plugins { id 'groovy' id 'java-library' } repositories { mavenCentral() } dependencies { implementation 'org.codehaus.groovy:groovy-all:3.0.17' // 版本需匹配你的Gradle版本 } sourceSets { main { resources { srcDirs = ['src/main/resources'] } } }
2. 自定义注解(MyAnnotation.groovy)
定义编译期生效的注解:
package com.example.annotations import java.lang.annotation.ElementType import java.lang.annotation.Retention import java.lang.annotation.RetentionPolicy import java.lang.annotation.Target @Retention(RetentionPolicy.SOURCE) @Target(ElementType.METHOD) @interface MyAnnotation { String value() default "default" }
3. AST转换逻辑(MyASTTransformation.groovy)
实现AST转换接口,给标注注解的方法插入前置逻辑:
package com.example.ast import org.codehaus.groovy.ast.ASTNode import org.codehaus.groovy.ast.MethodNode import org.codehaus.groovy.control.CompilePhase import org.codehaus.groovy.control.SourceUnit import org.codehaus.groovy.transform.ASTTransformation import org.codehaus.groovy.transform.GroovyASTTransformation @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS) class MyASTTransformation implements ASTTransformation { @Override void visit(ASTNode[] nodes, SourceUnit sourceUnit) { // 校验输入节点有效性 if (nodes.length < 2 || !(nodes[0] instanceof MethodNode)) { return } MethodNode targetMethod = (MethodNode) nodes[0] // 插入打印语句到方法开头 def printStmt = new org.codehaus.groovy.ast.stmt.ExpressionStatement( new org.codehaus.groovy.ast.expr.MethodCallExpression( new org.codehaus.groovy.ast.expr.VariableExpression("this"), new org.codehaus.groovy.ast.expr.ConstantExpression("println"), new org.codehaus.groovy.ast.expr.ArgumentListExpression( new org.codehaus.groovy.ast.expr.ConstantExpression("AST注入逻辑执行: " + targetMethod.name) ) ) ) targetMethod.code.statements.add(0, printStmt) } }
4. 注册AST转换类
在ast-transform/src/main/resources/META-INF/services/下创建文件org.codehaus.groovy.transform.ASTTransformation,内容为转换类的全限定名:
com.example.ast.MyASTTransformation
三、业务模块配置与使用
1. 模块构建脚本(app-module/build.gradle)
关键是确保Groovy编译时能访问到AST转换模块的字节码和配置:
plugins { id 'groovy' id 'application' } repositories { mavenCentral() } dependencies { implementation project(':ast-transform') implementation 'org.codehaus.groovy:groovy-all:3.0.17' } application { mainClass = 'com.example.app.MyService' } // 核心配置:让Groovy编译任务包含AST模块的输出 tasks.withType(GroovyCompile) { classpath += project(':ast-transform').sourceSets.main.output }
2. 业务代码中使用注解(MyService.groovy)
package com.example.app import com.example.annotations.MyAnnotation class MyService { @MyAnnotation void executeBusiness() { println("业务逻辑执行") } static void main(String[] args) { new MyService().executeBusiness() } }
四、验证运行
在根项目目录执行命令:
./gradlew app-module:run
预期输出:
AST注入逻辑执行: executeBusiness 业务逻辑执行
注意事项
- 版本兼容:Groovy版本必须与Gradle版本匹配(如Gradle 7.x对应Groovy 3.x,Gradle 8.x对应Groovy 4.x)
- 编译时依赖:业务模块必须在编译阶段就能访问AST转换模块,不能仅设置runtime依赖
- 资源打包:AST模块的META-INF配置文件必须被正确打包到输出jar中,否则Groovy无法识别转换类
内容的提问来源于stack exchange,提问作者Derrops
相关产品推荐
相关产品推荐

