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

最近在做一些奇怪的东西,需要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

9

10

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(

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值