您的位置:首页 > 编程语言 > Lua

在JAVA中使用LUA脚本记,javaj调用lua脚本的函数(转)

2016-03-17 06:54 531 查看
最近在做一些奇怪的东西,需要Java应用能够接受用户提交的脚本并执行,网络部分我选择了NanoHTTPD提供基本的HTTP服务器支持,并在Java能承载的许多脚本语言中选择了很久,比如Rhino,Jython和JRuby之类,但它们都太过庞大,并且很难实现沙盒保护服务器环境。最后我的目光投向了Lua,那个被称为粘合剂的语言。遇到的第一个难题是选择所使用的库,纯Java实现的Lua解释器有很多,什么LuaJ,LuaJava,kahlua,还有不知名的mochalua,jill等等(好多好多),其中许多解释器是纯Java实现的,LuaJava则使用了JNI,考虑再三以后我选择了LuaJ,毕竟是纯Java实现,拿来就能用的。
LuaJ也有对应JME和JSE平台的,JSE版是JME版的超集,还带有LuaJava里的luajava模块,能够直接在.lua中调用Java方法,创建Java实例,是很方便的。
折腾了几天,觉得对LuaJ也有足够的了解了,于是把一些相关的代码整理如下:

1
2
3
4
5
6
7
8
9

// 创建一个Lua执行的全局环境。
LuaValue global = JsePlatform.debugGlobals();

// 获得loadstring变量,这个变量存储了一个方法,相当于JavaScript里的eval。
LuaValue loadstring = global.get("loadstring");
// 第一个call()方法是调用loadstring这个方法,其参数中使用了LueValue.valueOf()这个静态方法把Java的数据封装成Lua能够使用的数据,第二个call()方法是执行字符串中的表达式,结果是输出了“Hello world!”。
loadstring.call(LuaValue.valueOf("print('Hello world!')")).call();
// 与之类似的还有loadfile,不过它的作用是接受一个文件路径,读入这个文件的内容,执行时调用call。
global.get("loadfile").call("./test.lua").call();

LuaJ直到代码运行结束前都会阻塞线程,这时候开启一个新的线程专门运行即可,但坑爹的是LuaJ运行以后无法中断(即使你中断了它所在的线程),比如你的.lua中有一个while true do end循环,那么你将永远无法中断它,除非退出你的整个Java应用…
怎么样,有没有很坑爹?我谷歌了大半天,发现LuaJ好像是没有官方的解决方案的(同时讨论这类东西的少得可怜!)…我也曾迁移代码到LuaJava上,发现调用了L.close()方法也是不能中断执行,最后终于抓住了一根救命稻草。
这根稻草来自ComputerCraft,一个在MineCraft中模拟计算机的模组,也是使用的LuaJ,但是却能中断一段代码的执行,于是我用jd-gui查看了它的源代码,最终有效实现了LuaJ的执行中中断。

首先容我介绍一下Lua中的一些自带的方法:
debug.sethook()方法能够精确到每一个函数设置钩子回调,这个回调里可以做任何想要做的事情;
coroutine.create()方法能够创建一个协同线程,
coroutine.yield()方法能够暂停这个协同线程(这正是我们想要的),
coroutine.resume()方法用来恢复这个协同线程。
接下来看代码吧:

1
2
3
4
5
6
7
8
910
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

package net.airtheva;

import java.io.File;

import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.OneArgFunction;
import org.luaj.vm2.lib.ZeroArgFunction;
import org.luaj.vm2.lib.jse.JsePlatform;

public class LuaWorker {

class _Worker implements Runnable {

@Override
public void run() {

mIsStopping = false;
mIsStopped = false;

// 产生协同线程。
mLuaThread = mCoroutineCreate.call(mLoadString.call(LuaValue.valueOf("while true do print('!') end")));

// 执行协同线程(该线程将被阻塞)。
mCoroutineResume.call(mLuaThread);

}

}

Thread mThread;

LuaValue mGlobal;

LuaValue mLoadString;

LuaValue mDebugSetHook;

LuaValue mNativeCoroutineCreate;
LuaValue mCoroutineCreate;
LuaValue mCoroutineYield;
LuaValue mCoroutineResume;

LuaValue mLuaThread;

boolean mIsStopping = true;
boolean mIsStopped = true;

public LuaWorker() {

mGlobal = JsePlatform.debugGlobals();

mLoadString = mGlobal.get("loadstring");

mDebugSetHook = mGlobal.get("debug").get("sethook");

LuaValue coroutine = mGlobal.get("coroutine");
mNativeCoroutineCreate = coroutine.get("create");
coroutine.set("create", new OneArgFunction() {

@Override
public LuaValue call(LuaValue value) {
Debug.L("Called.");
LuaThread thread = mNativeCoroutineCreate.call(value).checkthread();
mDebugSetHook.invoke(new LuaValue[] {
thread,
new OneArgFunction() {
@Override
public LuaValue call(LuaValue value) {
if(mIsStopping) {
//LuaThread.yield(LuaValue.NIL);
mCoroutineYield.call(); // 暂停本线程,上面那行也能起到一样的效果。
mIsStopped = true;
}
return LuaValue.NIL;
}
},
LuaValue.valueOf("crl"), // 这里ComputerCraft用的是LuaValue.NIL,但我这边好像停不下来…
LuaValue.valueOf(100000) // 这个100000是照着抄的,其实我不知道这是啥意思,等深入使用Lua了应该就会知道了。
});
return thread;
}

});

mCoroutineCreate = coroutine.get("create");
mCoroutineYield = coroutine.get("yield");
mCoroutineResume = coroutine.get("resume");

}

public void Start() {

mThread = new Thread(new _Worker());
mThread.start();

}

public void Stop() {

// 可能回收没做好。

mIsStopping = true;
mThread.interrupt();
mThread = null;

}

}

然后捣鼓LuaJava的时候发现在eclipse中能够正常运行,导出成.jar以后LuaJava工作不正常,折腾了两天后终于发现原来是编码问题,如果你也出现了问题可以试着指定-Dfile.encoding=UTF-8(坑爹的Windows)。但是因为LuaJava也不知道怎么才能停止,而且它的接口并没有这么丰富,所以最后还是回到了LuaJ的怀抱,这里只是记录一下(毕竟坑了我两天!)。
http://airtheva.net/wordpress/?p=159
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: