groovy因为其动态性经常被用来维护一些经常变化的业务规则,嵌入到应用中执行,达到可以灵活变更维护效果。 如如下脚本:
if(order.containsAttribute("test"))
return "AFTER_PAY"
if(isCOD)
return "BEFORE_PAY"
通过分析,可以得出以上脚本需要传入参数 order
和isCOD
.
使用以上脚本时会带来一个问题,调用者需要分析才可得出order
和isCOD
两个变量。
尤其对于一个长的规则脚本来说,人为分析更是麻烦且容易出错。如果能自动分析并得到结果会更好。
基于此研究了下groovy的AST树分析的vistor模式,可以实现自动分析出脚本里需要的信息。如变量应用。
import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
import org.codehaus.groovy.ast.DynamicVariable;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.control.SourceUnit;
import java.util.HashSet;
import java.util.Set;
/**
* @since 14-4-14
*/
public class CustomGroovyVistor extends ClassCodeVisitorSupport {
private Set<String> dynamicVariables = new HashSet<String>();
private Set<String> methodNames = new HashSet<String>();
/**覆写父类的方法,实现对变量节点的分析和记录**/
public void visitVariableExpression(VariableExpression expression) { //变量表达式分析
super.visitVariableExpression(expression);
Expression e = expression.getInitialExpression();
if (expression.getAccessedVariable() instanceof DynamicVariable) {
dynamicVariables.add(expression.getName());
}
}
public void visitMethodCallExpression(MethodCallExpression call) {
super.visitMethodCallExpression(call);
String methodName = call.getMethodAsString();
if (methodName != null && methodName.startsWith("f_")) {
methodNames.add(call.getMethodAsString());
}
}
@Override
protected SourceUnit getSourceUnit() {
return null;
}
public Set<String> getDynamicVariables() {
return dynamicVariables;
}
public void setDynamicVariables(Set<String> dynamicVariables) {
this.dynamicVariables = dynamicVariables;
}
public Set<String> getMethodNames() {
return methodNames;
}
public void setMethodNames(Set<String> methodNames) {
this.methodNames = methodNames;
}
}
String script="..."
List<ASTNode> nodes = new AstBuilder().buildFromString(script);
CustomGroovyVistor variableScopeVisitor = new CustomGroovyVistor();
for (ASTNode node : nodes) {
node.visit(variableScopeVisitor);
}
for(String v:variableScopeVisitor.getDynamicVariables()){
System.out.println(v);
}
以上结果即可得到该脚本的变量引用