Java使用Aviator表达式 学习记录(二十一)

1,368 阅读3分钟

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

使用 Java 自定义模块

除了可以用 AviatorScript 来定义模块之外,也可以用 Java 来定义。 Java 实现模块就是一个普通的 Java 类,它的所有静态方法将作为模块方法提供。

我们来实现一个最简单的 str 模块:

  @Import(ns = "str")
  public static class StringModule {
    public static boolean isBlank(final String s) {
      return s == null || s.trim().length() == 0;
    }
  }

Import  annotation 指定了模块的 namespace 名称为 str ,提供了一个静态方法 isBlank(s) 来判断字符串是否是空白的。

接下来我们使用 addModule 来添加模块到执行引擎:

 AviatorEvaluator.getInstance().addModule(StringModule.class);

添加之后,就可以用 require 来加载模块,并在脚本里使用:

 String script = "let str = require('str'); str.isBlank(s) ";

    System.out.println(AviatorEvaluator.execute(script, AviatorEvaluator.newEnv("s", "hello")));
    System.out.println(AviatorEvaluator.execute(script, AviatorEvaluator.newEnv("s", " ")));
    System.out.println(AviatorEvaluator.execute(script, AviatorEvaluator.newEnv("s", null)));

输出 :

false
true
true

你可以使用类似的方法来自定义模块。

Java Scripting API 支持

6.3 节我们看到了如何在 AviatorScript 中调用 Java 函数,这里我们将介绍如何用 Java 提供的脚本 API 来调用 AviatorScript 脚本中的函数等。

AviatorScript 内置了对 ****Java Scripting API 的支持,并且提供了 AviatorScriptEngineFactory 的 SPI 实现,只要你的 classpath 包含了 aviator 的 jar 引用,就可以直接使用。我们来看一些例子(所有示例代码在源码 example 的 scripting 目录)。

获取执行引擎

通过 ScriptEngineManager 可以获得 AviatorScript 的执行引擎:

package com.googlecode.aviator.example.scripting;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class ScriptEngineExample {
  public static void main(final String[] args) {
    final ScriptEngineManager sem = new ScriptEngineManager();
    ScriptEngine engine = sem.getEngineByName("AviatorScript");

  }
}

接下来我们将使用这个 engine 做各种例子演示。

配置执行引擎

可以从 ScriptEngine 里获取底层的 AviatorEvaluatorInstance 引用,进行引擎的相关配置:

package com.googlecode.aviator.example.scripting;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import com.googlecode.aviator.AviatorEvaluatorInstance;
import com.googlecode.aviator.Feature;
import com.googlecode.aviator.Options;
import com.googlecode.aviator.script.AviatorScriptEngine;

public class ConfigureEngine {
  public static void main(final String[] args) throws Exception {
    final ScriptEngineManager sem = new ScriptEngineManager();
    ScriptEngine engine = sem.getEngineByName("AviatorScript");
    AviatorEvaluatorInstance instance = ((AviatorScriptEngine) engine).getEngine();
    // Use compatible feature set
    instance.setOption(Options.FEATURE_SET, Feature.getCompatibleFeatures());
    // Doesn't support if in compatible feature set mode.
    engine.eval("if(true) { println('support if'); }");
  }
}

默认的引擎处于下列模式:

  1. 全语法特性支持
  2. 缓存编译模式
  1. 启用基于反射的 java 方法调用

求值

最简单的,你可以直接执行一段 AviatorScript 脚本,调用 eval(script) 方法即可

package com.googlecode.aviator.example.scripting;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class EvalScriptExample {
  public static void main(final String[] args) throws Exception {
    final ScriptEngineManager sem = new ScriptEngineManager();
    ScriptEngine engine = sem.getEngineByName("AviatorScript");
    engine.eval("print('Hello, World')");
  }
}

这将打印 Hello, World 到控制台,调用了 print 函数,

如果你的脚本是文件,也可以用 eval(reader) 方法:

import javax.script.*;
public class EvalFile {
    public static void main(String[] args) throws Exception {
        // create a script engine manager
        ScriptEngineManager factory = new ScriptEngineManager();
        // create AviatorScript engine
        ScriptEngine engine = factory.getEngineByName("AviatorScript");
        // evaluate AviatorScript code from given file - specified by first argument
        engine.eval(new java.io.FileReader(args[0]));
    }
}

文件名通过执行的第一个参数指定。

默认引擎处于缓存表达式模式。

注入变量

可以注入全局变量到脚本,并执行:

package com.googlecode.aviator.example.scripting;

import java.io.File;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class ScriptVars {
  public static void main(final String[] args) throws Exception {
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("AviatorScript");

    File f = new File("test.txt");
    // expose File object as variable to script
    engine.put("file", f);

    // evaluate a script string. The script accesses "file"
    // variable and calls method on it
    engine.eval("print(getAbsolutePath(file))");
  }

}

这里我们将文件 f 通过 engine.put 方法作为全局变量注入,然后执行脚本 print(getAbsolutePath(file)) ,打印文件的绝对路径。

默认引擎启用了基于 java 反射的方法调用模式。