Groovy编译时元编程 ( 编译时方法拦截 | 在 MyASTTransformation#visit 方法中进行方法拦截 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Groovy编译时元编程 ( 编译时方法拦截 | 在 MyASTTransformation#visit 方法中进行方法拦截 )相关的知识,希望对你有一定的参考价值。
文章目录
一、在 MyASTTransformation#visit 方法中进行方法拦截
在上一篇博客 【Groovy】编译时元编程 ( 编译时方法拦截 | 在 MyASTTransformation#visit 方法中找到要拦截的方法 ) 中 , 在MyASTTransformation#visit 方法中 , 首先获取了 ModuleNode , 然后查找指定的 ClassNode , 从指定的 ClassNode 中查找对应的 MethodNode 节点 ;
方法拦截主要是在 MethodNode 节点中执行 ; 该 MethodNode 节点对应 Student 类的 hello 方法 ;
根据 【Groovy】编译时元编程 ( 方法拦截时用到的 AST 语法树节点 MethodNode 节点 | MethodNode 节点分析 | MethodNode 节点中的BlockStatement) 博客分析 , MethodNode 节点中封装了 private Statement code;
成员 , 该 code 成员的实际类型是 BlockStatement 类型 ;
public class BlockStatement extends Statement
这里首先将 MethodNode 节点的 code 成员赋值给 BlockStatement , 相当于将 Statement 对象转为 BlockStatement 类型 ;
BlockStatement blockStatement = code
在 BlockStatement 对象中 , 封装了 private List<Statement> statements = new ArrayList<Statement>();
成员 , 这里面就是该 MethodNode 节点中的方法内容 , 将该集合清空 , 就相当于将方法体清空了 , 实现了方法拦截操作 ;
二、完整代码示例及进行编译时处理的编译过程
1、Groovy 脚本 Groovy.groovy
class Student
def name
def hello()
println "hello"
def student = new Student()
student.hello()
2、ASTTransformation 接口实现 MyASTTransformation.groovy
import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.ast.builder.AstBuilder
import org.codehaus.groovy.ast.stmt.BlockStatement
import org.codehaus.groovy.control.SourceUnit
import org.codehaus.groovy.transform.ASTTransformation
import org.codehaus.groovy.transform.GroovyASTTransformation
@GroovyASTTransformation
class MyASTTransformation implements ASTTransformation
/**
* 编译时处理方法
* @param nodes AST 抽象语法树节点 , 是 ASTNode 数组类型
* @param source 源单元 , 可以通过该对象拿到源文件
*/
@Override
void visit(ASTNode[] nodes, SourceUnit source)
println nodes
println source
println source.AST
println source.source.reader.text
// 获取 Groovy.groovy 脚本中的类集合 , 并进行遍历
// 在 ModuleNode 中的类节点封装在了如下成员中
// List<ClassNode> classes = new LinkedList<ClassNode>();
source.AST.classes.find
// 查找名称为 Student 的类
// it 是 ClassNode 节点
it.name == "Student"
?.methods?.find
// 查找 Student 类下名称为 hello 的方法
// it 是 MethodNode 节点
it.name == "hello"
?.with
// 找到了 Student 下的 hello 方法
// 在 MethodNode 节点下调用
// it 就是 MethodNode 节点
BlockStatement blockStatement = code
// 清空 BlockStatement 中的 List<Statement> statements 成员
// 方法拦截清空 , 就不再执行原本的方法
// 方法注入不清空 , 会执行原来的方法内容
blockStatement.statements.clear()
3、配置 ASTTransformation
创建 D:\\002_Project\\012_Groovy\\Groovy_Demo\\src\\main\\groovy\\resources\\META-INF\\servicesorg.codehaus.groovy.transform.ASTTransformation
目录层级及文件 , 在文件中配置 ASTTransformation
实现类的全类名 :
MyASTTransformation
3、使用命令行进行编译时处理
首先 , 进入 D:\\002_Project\\012_Groovy\\Groovy_Demo\\src\\main\\groovy
目录 ,
cd D:\\002_Project\\012_Groovy\\Groovy_Demo\\src\\main\\groovy
然后 , 编译 编译时处理类 MyASTTransformation.groovy , 将编译后的字节码文件 MyASTTransformation.class
保存到 D:\\002_Project\\012_Groovy\\Groovy_Demo\\src\\main\\groovy\\classes
目录下 ,
groovyc -d classes MyASTTransformation.groovy
再后 , 打包上述编译好的字节码文件 , 存放在 D:\\002_Project\\012_Groovy\\Groovy_Demo\\src\\main\\groovy\\test.jar
路径 ;
jar -cf test.jar -C classes . -C resources .
最后 , 依赖 test.jar 执行 Groovy.groovy 脚本
groovy -classpath test.jar Groovy.groovy
执行结果为 :
[org.codehaus.groovy.ast.ModuleNode@7d7758be]
org.codehaus.groovy.control.SourceUnit@2bdd8394
org.codehaus.groovy.ast.ModuleNode@7d7758be
class Student
def name
def hello()
println "hello"
def student = new Student()
student.hello()
以上是关于Groovy编译时元编程 ( 编译时方法拦截 | 在 MyASTTransformation#visit 方法中进行方法拦截 )的主要内容,如果未能解决你的问题,请参考以下文章
Groovy编译时元编程 ( 方法拦截时用到的 AST 语法树节点 MethodNode 节点 | MethodNode 节点分析 | MethodNode 节点中的BlockStatement)
Groovy编译时元编程 ( 编译时元编程引入 | 声明需要编译时处理的类 | 分析 Groovy 类的 AST 语法树 )
Groovy编译时元编程 ( ASTTransformation#visit 方法简介 | org.codehaus.groovy.ast.ModuleNode 脚本节点 )
Groovy编译时元编程 ( 编译时方法注入 | 使用 buildFromSpecbuildFromStringbuildFromCode 进行方法注入 )