在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();
    mThread = null;
   
  }
 
}

然后捣鼓LuaJava的时候发现在eclipse中能够正常运行,导出成.jar以后LuaJava工作不正常,折腾了两天后终于发现原来是编码问题,如果你也出现了问题可以试着指定-Dfile.encoding=UTF-8(坑爹的Windows)。但是因为LuaJava也不知道怎么才能停止,而且它的接口并没有这么丰富,所以最后还是回到了LuaJ的怀抱,这里只是记录一下(毕竟坑了我两天!)。

http://airtheva.net/wordpress/?p=159

时间: 2024-10-18 13:28:20

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

java中多线程执行时,为何调用的是start()方法而不是run()方法

Thead类中start()方法和run()方法的区别 1,start()用来启动一个线程,当调用start()方法时,系统才会开启一个线程,通过Thead类中start()方法来启动的线程处于就绪状态(可运行状态),此时并没有运行,一旦得到CPU时间片,就自动开始执行run()方法.此时不需要等待run()方法执行完也可以继续执行下面的代码,所以也由此看出run()方法并没有实现多线程. 2,run()方法是在本线程里的,只是线程里的一个函数,而不是多线程的.如果直接调用run(),其实就相当

Lua学习笔记--C调用Lua

Lua是一种嵌入式语言,可以很好的嵌入其他应用程序.lua为我们提供了一组灵活的C API,使C代码能够很好的与Lua进行交互.包括读写Lua全局变量,调用Lua函数,运行Lua代码,注册C函数反过来供Lua调用.简单的说,C能调用Lua,反过来Lua也能调用C.真的是灰常强大灵活的脚本!!现在,先来学习一下怎么用C调用Lua. 其实最简单的我们已经做过了,通过一个dofile,运行一个lua脚本文件. 一.栈 Lua与C的交互是通过一个虚拟栈进行的,这个栈对于Lua来说是严格的LIFO(后进先

黑马程序员-java中方法的知识点和递归调用

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 方法执行原理:(方法不调用不执行,调用才执行)  *   方法在调用的这时候,才会在内存中划分空间  *   方法在调用的时候,是在栈内存中分配的空间(jvm有一块内存是栈内存) * 函数/方法目的: 还是为了代码重用  * 相同的类型的

java中方法的知识点和递归调用

 方法执行原理:(方法不调用不执行,调用才执行) *   方法在调用的这时候,才会在内存中划分空间 *   方法在调用的时候,是在栈内存中分配的空间(jvm有一块内存是栈内存) * 函数/方法目的: 还是为了代码重用 * 相同的类型的操作,不容重复的写代码 * 函数/方法:就是一段有名字的代码段 * 方法的定义 *  [方法修饰符列表] 方法返回值类型 方法名(参数1,参数2,参数3....){ *          执行语句; *  } * *  方法修饰符列表是可选的:权限控制的:publi

java中获取所有文件--(递归调用)

import java.io.File;import java.io.*; //获取一个文件夹中的所有的文件.  /*    打印要求:      -- a.txt   -- IO.doc      -- ~$IO.doc   -- 代码   -- --.metadata   -- --Day18   --视频   -- --01 线程通信.wmv   -- --02 守护线程和join方法.wmv   -- --03 Filed的创建.wmv   -- --04 File的常用方法.wmv  

java中的小数的四舍五入取整的几种函数

Math类中提供了5个与取整相关的函数,如下所示: static double ceil(double a):天花板函数,返回大于等于a的最小整数(但是以浮点数形式存储). static double floor(double a):地板函数,返回小于等于a的最大整数(但是以浮点数形式存储). static double rint(double a):四舍五入函数,返回与a的值最相近的整数(但是以浮点数形式存储). static long round(double a):四舍五入函数,返回与a的

Java中的try catch finaly先后调用顺序

自我总结,有什么不足或好的方案,希望大家给予纠正,感激不尽! 目的:try catch finaly的顺序执行,和大家复习一遍. 方法:debug来确认执行顺序.(需要引入junit包) 废话不多说,debug是检验代码执行顺序的唯一标准,哈哈... 测试一: 新建测试类:ExceptionTest package com.core.test007; import org.junit.Test; public class ExceptionTest { @Test public void mai

java中字符串数组、字符串、调用split方法后长度比较

通过eclipse测试: String temp2 = ""; String[] temp = temp2.split(","); String[] temp3 = {}; System.out.println("............................."+temp2.length()); System.out.println("***************"+temp.length); System.ou

深入lua栈交互—cpp调用lua数据

lua是通过lua_state这个栈来和c 交互的 1.....lua栈 index 下往上增长 如: 1 2 3 4 5 6 2.....lua栈 index 是循环的 如下 index 上到下 是 3 2 1 0 -1 -2 -3 ,栈对应的值为     1     2     3     x     1     2     3      3......lua函数多个返回值如果上面是function返回了3个返回值,那么return a ,b,c  中 a=3 b=2 c=1 第一个返回值先