Aviator源码:从具体实例看Aviator属性语法糖源码分析
(a.b.c)
⽬录
1.从测试⼊⼿直观iator特性
variable used in lambdaa.b.c测试代码如下:
public class BillingEngineTest extends TransactionalTestBase {
@Test
public void test() {
Student student = new Student();
student.setName("张三");
student.setAge(20);
student.setBirthday(DateUtils.parse("1995-01-01 10:00:00", DateUtils.YYYYMMDDHHMMSS));
student.setCardId(1000L);
student.wArrayList("李四", "王五"));
student.setScore(new BigDecimal("100.00"));
student.setMonitor(true);
student.setLevel("A");
Map env = wHashMap();
env.put("student", student);
Object name = ute("student.name", env);
assertThat(name, is("张三"));
}
}
运⾏结果:
"张三",测试通过;
可以看出通过变量逐级引⽤的⽅式,可以正确获取对应字段的属性值,下⾯从aviator源码⼊⼿来具体分析aviator是怎么⽀持的(How);
2.Aviator可选项⽀持
属性语法糖在aviator中是默认开启⽀持的,在Options类中可以看到:
3.源码追踪
这⾥获取脚本的计算结果主要分为2步:
1): 通过ASM 字节码技术构造ClassExpression对象;
2): 调⽤ClassExpression的execute0⽅法获取结果值;
3.1 通过ASM 字节码技术构造ClassExpression对象
⾸先说明⼏个主要⽤到的类:
ExpressionLexer:表达式词法分析器,⽤来对aviator脚本进⾏词法解析,如将脚本解析为变量、数字、字符串、注释等;
CodeGenerator:字节码⽣成器,⽤于动态⽣成⾃定义的字节码;
ExpressionParser:表达式解析器,⽤于将脚本编译为表达式对象(BaseExpression)
下⾯是aviator中通过ASM⼯具动态⽣成字节码的过程,如下:
1.⽣成ClassExpression⼦类字节码
public ASMCodeGenerator(final AviatorEvaluatorInstance instance, final String sourceFile,
final AviatorClassLoader classLoader, final OutputStream traceOut) {
this.classLoader = classLoader;
this.instance = instance;
thispileEnv = new Env();
this.sourceFile = sourceFile;
thispileEnv.setInstance(this.instance);
// Generate inner class name
this.className = "Script_" + System.currentTimeMillis() + "_" + AndIncrement();
// Auto compute frames
this.classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
// if (trace) {
// aceClassVisitor = new TraceClassVisitor(this.clazzWriter, new PrintWriter(traceOut));
// this.classWriter = new aceClassVisitor);
// } else {
// this.classWriter = new CheckClassAdapter(this.clazzWriter);
// }
visitClass();
}
private void visitClass() {
this.classWriter.visit(BytecodeVersion(), ACC_PUBLIC + ACC_SUPER,
this.className, null, "com/googlecode/aviator/ClassExpression", null);
this.classWriter.visitSource(this.sourceFile == null ? this.className : this.sourceFile, null);
}
2.⽣成ClassExpression⼦类成员变量,f1,类型AviatorJavaType
public void initVariables(final Map<String, VariableMeta/* counter */> vars) {
this.variables = vars;
this.innerVars = new HashMap<>(this.variables.size());
for (String outterVarName : this.variables.keySet()) {
// Use inner variable name instead of outter variable name
String innerVarName = getInnerName(outterVarName);
this.innerVars.put(outterVarName, innerVarName);
this.classWriter.visitField(ACC_PRIVATE + ACC_FINAL, innerVarName,
"Lcom/googlecode/aviator/runtime/type/AviatorJavaType;", null, null).visitEnd();
}
}
3.⽣成ClassExpression⼦类默认构造函数:
/**
* Make a default constructor
*/
private void makeConstructor() {
this.mv = this.classWriter.visitMethod(ACC_PUBLIC, CONSTRUCTOR_METHOD_NAME,
"(Lcom/googlecode/aviator/AviatorEvaluatorInstance;Ljava/util/List;Lcom/googlecode/aviator/lexer/SymbolTable;)V",
null, null);
this.mv.visitCode();
this.mv.visitVarInsn(ALOAD, 0);
this.mv.visitVarInsn(ALOAD, 1);
this.mv.visitVarInsn(ALOAD, 2);
this.mv.visitVarInsn(ALOAD, 3);
this.mv.visitMethodInsn(INVOKESPECIAL, "com/googlecode/aviator/ClassExpression",
CONSTRUCTOR_METHOD_NAME,
"(Lcom/googlecode/aviator/AviatorEvaluatorInstance;Ljava/util/List;Lcom/googlecode/aviator/lexer/SymbolTable;)V");
if (!this.innerVars.isEmpty()) {
for (Map.Entry<String, String> entry : Set()) {
String outterName = Key();
String innerName = Value();
this.mv.visitVarInsn(ALOAD, 0);
this.mv.visitTypeInsn(NEW, JAVA_TYPE_OWNER);
this.mv.visitInsn(DUP);
this.mv.visitLdcInsn(outterName);
this.mv.visitVarInsn(ALOAD, 3);
this.mv.visitMethodInsn(INVOKESPECIAL, JAVA_TYPE_OWNER, CONSTRUCTOR_METHOD_NAME,
"(Ljava/lang/String;Lcom/googlecode/aviator/lexer/SymbolTable;)V");
this.mv.visitFieldInsn(PUTFIELD, this.className, innerName,
"Lcom/googlecode/aviator/runtime/type/AviatorJavaType;");
}
}
if (!this.innerMethodMap.isEmpty()) {
for (Map.Entry<String, String> entry : Set()) {
String outterName = Key();
String innerName = Value();
this.mv.visitVarInsn(ALOAD, 0);
this.mv.visitVarInsn(ALOAD, 1);
this.mv.visitLdcInsn(outterName);
this.mv.visitVarInsn(ALOAD, 3);
this.mv.visitMethodInsn(INVOKEVIRTUAL, "com/googlecode/aviator/AviatorEvaluatorInstance",
"getFunction",
"(Ljava/lang/String;Lcom/googlecode/aviator/lexer/SymbolTable;)Lcom/googlecode/aviator/runtime/ty
pe/AviatorFunction;"); this.mv.visitFieldInsn(PUTFIELD, this.className, innerName,
"Lcom/googlecode/aviator/runtime/type/AviatorFunction;");
}
}
if (!stantPool.isEmpty()) {
for (Map.Entry<Token<?>, String> entry : Set()) {
Token<?> token = Key();
String fieldName = Value();
this.mv.visitVarInsn(ALOAD, 0);
onConstant0(token, true);
this.popOperand();
this.mv.visitFieldInsn(PUTFIELD, this.className, fieldName, OBJECT_DESC);
}
}
this.mv.visitInsn(RETURN);
this.mv.visitMaxs(4, 1);
this.mv.visitEnd();
}
4.构造ClassExpression⼦类⽅法execute0():
private void startVisitMethodCode() {
this.mv = this.classWriter.visitMethod(ACC_PUBLIC + +ACC_FINAL, "execute0",
"(Lcom/googlecode/aviator/utils/Env;)Ljava/lang/Object;",
"(Lcom/googlecode/aviator/utils/Env;)Ljava/lang/Object;", null);
this.mv.visitCode();
}
进⼊⽅法体,并⽣成⽅法体内容:
// Get field at first time
this.mv.visitVarInsn(ALOAD, 0);
this.mv.visitFieldInsn(GETFIELD, this.className, innerVarName,
"Lcom/googlecode/aviator/runtime/type/AviatorJavaType;");
// Variable is used more than once,store it to local
if ((outterVarName).getRefs() > 1) {
this.mv.visitInsn(DUP);
int localIndex = getLocalIndex();
this.mv.visitVarInsn(ASTORE, localIndex);
if (name2Index == null) {
name2Index = new HashMap<>();
this.labelNameIndexMap.put(this.currentLabel, name2Index);
}
name2Index.put(innerVarName, localIndex);
this.pushOperand(3);
this.popOperand(2);
} else {
this.pushOperand(2);
this.popOperand();
}
loadEnv();
this.mv.visitMethodInsn(INVOKEVIRTUAL, OBJECT_OWNER, "getValue",
"(Ljava/util/Map;)Ljava/lang/Object;");
this.mv.visitInsn(ARETURN);
this.popOperand();
this.popOperand();
this.mv.visitMaxs(this.maxStacks, this.maxLocals);
this.mv.visitEnd();
⾄此,通过ASM字节码技术⽣成字节码完毕。
根据ASM指令语义,可以推导出上述动态⽣成的字节码反编译结果如下:
public class SubClassExpression extends ClassExpression {
private final AviatorJavaType f1;
public SubClassExpression(final AviatorEvaluatorInstance instance, final List<String> varNames, final SymbolTable symbolTable){
super(instance, varNames, symbolTable);
f1 = new AviatorJavaType("student.name", symbolTable);
}
public final Object execute0(Env env){
Value(env);
}
}
5.字节码构造完毕,根据字节码⽣成Expression class对象:
@Override
public Expression getResult(final boolean unboxObject) {
end(unboxObject);
byte[] bytes = ByteArray();
try {
Class<?> defineClass =
ClassDefiner.defineClass(this.className, Expression.class, bytes, this.classLoader);
Constructor<?> constructor =
new ArrayList<VariableMeta>(this.variables.values()), this.symbolTable);
exp.setLambdaBootstraps(this.lambdaBootstraps);
exp.setFuncsArgs(this.funcsArgs);
exp.setSourceFile(this.sourceFile);
return exp;
} catch (ExpressionRuntimeException e) {
throw e;
} catch (Throwable e) {
if (e.getCause() instanceof ExpressionRuntimeException) {
throw (ExpressionRuntimeException) e.getCause();
}
throw new CompileExpressionErrorException("define class error", e);
}
}
3.2 调⽤ClassExpression的execute0⽅法获取结果值
1.调⽤BaseExpression的execute⽅法
/**
* Execute a text expression with environment
*
* @param expression text expression
* @param env Binding variable environment
* @param cached Whether to cache the compiled result,make true to cache it.
*/
public Object execute(final String expression, final Map<String, Object> env,
final boolean cached) {
Expression compiledExpression = compile(expression, cached);
if (compiledExpression != null) {
ute(env);
} else {
throw new ExpressionNotFoundException("Null compiled expression for " + expression);
}
}
execute⽅法实现如下:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论