java平台使用脚本语言

2 篇文章 0 订阅
1 篇文章 0 订阅

Java平台使用脚本语言

​ java平台可以使用的脚本语言

  1. js
  2. groovy
  3. Renjin
  4. sisc

使用java提供的脚本引擎对脚本语言进行解析

​ java提供了一个脚本引擎:ScriptEngine,我们需要通过这个脚本引擎来对我们的脚本语言进行解析。

获取ScriptEngine

​ 构造一个ScriptEngineManager,并调用getEngineByxx方法来获取对应的ScriptEngine

//构建一个脚本引擎管理器
ScriptEngineManager manager = new ScriptEngineManager();

//获取js的解析引擎
ScriptEngine jsEngine = manager.getEngineByName("js");

获取当前java所支持的引擎名,MIME类型和文件扩展名

​ 可使用ScriptEngineManager 的getEngineFactories()方法来获取。

ScriptEngineManager manager = new ScriptEngineManager();
List<ScriptEngineFactory> factories = manager.getEngineFactories();

​ jdk1.8,当前内置只支持一个脚本引擎:Nashorn;

​ 这是有Oracle开发的一个js解释器,如果想用使用其他脚本语言的解释器,可以通过在类路径中提供必要的jar包来添加对更多语言的支持。----《java核心技术卷二》 p353

使用js脚本引擎解析js脚本

简单运行

​ 以下代码仅仅对于js脚本解析器的简单使用,通过jsEngine.eval();方法传入一段脚本,或者一个js文件输入流;脚本的内容也很简单就是将var a = 10;然后通过jsEngine.get(“key”),方法从脚本中读取一个var变量进行输出;但这远远不是js脚本引擎的所有功能。

public static void main(String[] args) throws Exception {

    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine jsEngine = manager.getEngineByName("js");

    //直接使用string 模拟脚本语言进行测试
    String jsScript = "var a = 10";
    jsEngine.eval(jsScript);
    int strA = (int)jsEngine.get("a");
    System.out.println(strA);
    //使用js脚本文件进行测试
    File file = new File("test.js");

    if (!file.exists()) {
        return;
    }

    Reader reader = new FileReader(file);

    jsEngine.eval(reader);
    int fileA = (int)jsEngine.get("a");
    System.out.println(fileA);
}

ScriptEngine中的方法

  • eval(“script”):执行传入的脚本,如果该脚本有返回值,就返回该值;

  • get(“key”):从脚本获取key对应的value

  • put"(“key”,value):在引擎作用域内传入一个key = value的键值对

  • createBindings():创建一个适合该引擎的空Bindings对象

  • getBindings():返回绑定的Bindings对象

  • setBindings():

  • getContext()

  • setContext()

  • getFactory()

引擎作用域和全局作用域

​ 引擎作用域:由ScriptEngine使用eval或者put方法,在脚本中构建的key:value键值对;

​ 全局作用域:有ScriptEngineManage使用put方法,在脚本中够构建的key:value键值对;

​ 其他作用域:实现ScriptContext接口的类,这些类可以作为自定义的作用域,由一个整数标识,越小的数字应该越先被搜索到。

Bindings对象

​ key:value:可以称为一个变量绑定;而Bindings对象可以存放多个key:value这样的绑定,而且可以在同一个作用域中的其他绑定的变量;

public static void main(String[] args) throws ScriptException {
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine jsEngine = manager.getEngineByName("js");
    Bindings jsBindings = jsEngine.createBindings();
    
    jsBindings.put("a",10);
    jsEngine.eval("var b = a",jsBindings);

    Object b = jsBindings.get("b");
    System.out.println(b);

    Object b2 = jsBindings.get("b");//10,说明 一个变量绑定是可以多次使用的
    System.out.println(b2);

    Object b4 = jsEngine.get("b");
    System.out.println(b4);//null, 说明在使用eval方法时传入一个Binding对象,传入脚本的变量绑定也会放在这个Binding对象中

    jsEngine.eval("var e = 30");
    Object e = jsEngine.get("e");
    System.out.println("e" + e);//30,说明如果没有传入Binding对象,则会放到jsEngine的公共域中

    Object b1 = manager.get("b");
    System.out.println(b1);//null 说明 b 变量 是属于 jsEngine的

    manager.put("c",20);
    Object c = jsEngine.get("c");
    System.out.println(c);// 20 说明 c 变量 是属于公公域的
}

重定向输入和输出

​ 可以通过脚本上下文(ScriptEngine)的setReader和SetWriter方法来重定向脚本的标准输入和输出

​ 如下数据,world就会被重定向到控制台输出

print("Hello");
java.lang.System.out.println("World");

​ 代码如下

public static void main(String[] args) throws Exception {
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine jsEngine = manager.getEngineByName("js");

    StringWriter writer = new StringWriter();//设置一个输出流
    jsEngine.getContext().setWriter(new PrintWriter(writer,true));//修改数据输出方式
    Reader reader = new FileReader(new File("redirct.js"));
    jsEngine.eval(reader);

}

​ 由于Nashorn引擎没有标准的输入源的概念,因此调用setReader没有效果。

​ 除了可以设置脚本正常运行的输出,也可以设置脚本运行出错的输出:

​ setErrorWriter(Writer writer);

调用脚本的函数和方法

​ 使用ScriptEngine调用javaScript或者其他脚本语言的方式有以下几种。

  • 使用脚本中的函数的函数名来调用: InvokeFunction()
  • 如果脚本语言是面向对象的,就可以使用: InvokeMethod()
  • 让脚本引擎去实现一个接口,通过这个接口的实例对象去调用脚本中的方法
InvokeFunction

​ 使用该方法调用脚本的函数需要注意的是,对应的脚本引擎必须实现了Invokeable接口,即可以使用java的代理机制。具体内容在《java核心技术卷一第6章》p258

​ 首先要在脚本文件中或者再脚本字符串中有一个方法;有无返回值并没有关系;例如我这边使用的是外置的js文件。

function greet(how, whom) {
    return how + ',' + whom + '!';
}

​ 然后使用ScriptEngine的eval方法将这个脚本文件传到这个引擎作用域中。

Reader reader = new FileReader(new File("jsFunction.js"));
jsEngine.eval(reader);//将脚本传入js解析器
//调用该脚本中的方法
Object result = ((Invocable) jsEngine).invokeFunction("greet", "hello", "world");
System.out.println(result);
//输出:hello,world!

​ 小结:使用invokeFunction使用java代码区调用js函数,首先需要将当前的ScriptEngine强转为Invocable接口类型,然后需要知道这个js函数的函数名,并且需要传入这个js函数需要的参数。这样就可以使用这个脚本中的函数了。

InvokeMethod

​ 如果脚本语言是面向对象的脚本语言,例如js;则可以使用InvokeMethod方法去调用当前脚本的函数。

function Greet(how) {
    this.how = how;
}

Greet.prototype.welcome= function (whom) {
    return this.how + ',' + whom + '!';
}

​ 上面的代码其实就是在js中申明了一个方法Greet,并且用这个方法的prototype对象又添加了一个方法welcome;

//将上述js文件传入当前引擎作用域
sEngine.eval(reader);
//实例化一个Greet方法的对象
Object yo = jsEngine.eval("new Greet('Yo')");
//传入当前Greet方法的对象,以及其内部方法welcome的方法名和参数
Object result = ((Invocable) jsEngine).invokeMethod(yo,"welcome","World");
//输出返回值
System.out.println(result);
//Yo,World

​ 小结:必须为面向对象的脚本语言;

让脚本引擎去实现一个java接口,使用这个接口的java方法去调用脚本中的函数。

​ 脚本中的方法名和参数必须和java接口中的方法名和参数一致。

​ js文件

function welcome(whom) {
    return 'hello' + whom + '!'
}

​ java代码:

​ 定义的接口

public interface Greeter {
    String welcome(String whom);
}

​ 实现

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine js = manager.getEngineByName("js");
js.eval(new FileReader(new File("jsFunctionInterface")));

//让当前脚本引擎实现Greeter接口,并返回这个接口的一个实例
Greeter g = ((Invocable) js).getInterface(Greeter.class);
//使用这个接口中的welcom方法去调用脚本中的函数
String world = g.welcome("world");
System.out.println(world);
//helloworld!

​ 在面向对象的脚本语言中,可以通过相匹配的java接口来访问一个脚本类;

//这里用到js代码是InvokeMethod中的js代码
jsEngine.eval(reader);
Object yo = jsEngine.eval("new Greet('Yo')");
Greeter g = ((Invocable) jsEngine).getInterface(yo, Greeter.class);
String world = g.welcome("World");
System.out.println(world);

编译脚本,提高脚本在jav中的执行效率

​ 如果当前的脚本引擎实现了Compilable接口,就可以将这些脚本代码编译为某种中间格式,提高执行效率。

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine jsEngine = manager.getEngineByName("js");
Reader reader = new FileReader(new File("test.js"));
CompiledScript script = null;
if (jsEngine instanceof Compilable) {
    script = ((Compilable)jsEngine).compile(reader);
}

if (script != null) {
    Object eval = script.eval();
    System.out.println(eval);
} else {
    Object eval = jsEngine.eval(reader);
    System.out.println("uncompilable" + eval);
}

​ 当前不是很清楚将脚本编译后该怎么调用脚本中的函数。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值