跳转至

在Java中使用脚本语言

在Java中使用脚本语言

更新日期: 2020-07-28


1. 概述

在Java6中,Java增加了一个叫做ScriptEngine的组件专门用来支持脚本语言。使用这个组件可以非常方便的与各种脚本语言进行交互。

并且,使用这个组件,可以让不同的脚本语言在使用时调用统一的接口。这样就可以获得非常相似的写法,降低了学习成本。因为每种脚本语言的包提供的接口函数可能差别很大。

2. 使用ScriptEngine

这里就以lua脚本语言为例来介绍下ScriptEngine的使用。其它脚本语言也是类似的使用方法。

2.1 准备工作

首先我们要在工程中引入如下的luaj包:

  • luaj-jse

在Maven中,可以很方便的引用:

Example

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.luaj/luaj-jse -->
<dependency>
    <groupId>org.luaj</groupId>
    <artifactId>luaj-jse</artifactId>
    <version>3.0.1</version>
</dependency>

2.2 初始化脚本引擎

我们主要使用ScriptEngine类来进行各种交互操作,创建这个类的过程如下:

1
2
3
4
5
// 脚本引擎管理器
ScriptEngineManager mgr = new ScriptEngineManager();

// 脚本引擎
ScriptEngine e = mgr.getEngineByName("lua");

这个类中比较重要的函数有这些:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Object  eval(String script)
// Executes the specified script.

Object  eval(Reader reader)
// Same as eval(String) except that the source of the script is provided as a Reader

Object  get(String key)
// Retrieves a value set in the state of this engine.

void    put(String key, Object value)
// Sets a key/value pair in the state of the ScriptEngine that may either create a Java Language Binding to be used in the execution of scripts or be used in some other way, depending on whether the key is reserved.
  • eval函数可以用来执行任意的脚本语言代码(从字符串或者文件中)。从变量定义到函数声明、函数调用都是可以的。并且在字符串中也支持使用换行符\n来写多行语句。
  • get函数用来获取lua中所定义的外部变量的值。通常用来从脚本语言向java返回计算结果。
  • put函数用来在java中向脚本语言中传递值,put一个值就相当于在脚本语言中创建了一个对应的变量。(可以传递java对象)

执行上下文

在脚本语言执行时,有一个执行环境或者叫执行上下文环境的概念。在默认情况下,脚本引擎会自动创建出一个上下文环境出来。

这样,所有的evalgetput函数执行的操作都是在同一个上下文中进行的。可以连续多次的执行eval函数。例如:在第一个eval中定义一些函数和变量,在后面的eval中来使用它们。getput函数也是同样的道理。

如果想要切换上下文环境,在ScriptEngine中也提供了相应的函数,这里就不多做介绍了。

2.3 常用的交互操作

直接用代码来演示比较直观:

读取脚本中的变量

代码:

1
2
3
4
e.eval("a = 1 + 1");
Object a = e.get("a");

System.out.println("a = " + a);

运行结果:

1
a = 2

设定脚本中的变量

代码:

1
2
3
4
5
e.eval("a = 1 + 1");
e.eval("print('a = ' .. a)");

e.put("a", 100);
e.eval("print('a = ' .. a)");

运行结果:

1
2
a = 2
a = 100

调用lua中的函数

代码:

1
2
3
4
5
6
7
// 先定义一个lua函数,带有两个参数
e.eval("function sayHello(str, num)\n" +
    "print('hello, this is a lua function. p1 = ' .. str .. ', p2 = ' .. num)" +
    "end");

// 在java代码中调用此函数
e.eval("sayHello('这是第一个参数', 2222)");

运行结果:

1
hello, this is a lua function. p1 = 这是第一个参数, p2 = 2222

调用java中的函数

代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 先定义一个java函数,这个方法一定要是`static`的,否则不能调用
public class MyJavaApi {

    public static void javaSayHello(String str, int num) {

        System.out.println("这是一个Java程序。p1 = " + str + ", p2 = " + num);
    }
}

// 调用此函数
e.put("MyJavaApi", new MyJavaApi());
e.eval("MyJavaApi:javaSayHello('这是个字符串参数', 2333)");

运行结果:

1
这是一个Java程序。p1 = 这是个字符串参数, p2 = 2333

执行脚本文件

代码:

1
2
3
4
-- 先定义一个lua脚本文件(在Maven的资源文件夹下面: lua/test.lua)
function func1()
    print("this is a lua file.")
end
1
2
3
4
5
6
7
8
9
// 然后在java中执行这个脚本文件,并且调用里面的方法:
// 读取文件
InputStream inputStream = App.class
        .getClassLoader().getResourceAsStream("lua/test.lua");
InputStreamReader reader = new InputStreamReader(inputStream);
// 执行脚本文件
e.eval(reader);
// 执行函数
e.eval("func1()");

运行结果:

1
this is a lua file.