zoukankan      html  css  js  c++  java
  • 在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

  • 相关阅读:
    LCS 最长公共子序列
    零和数组
    Learn2Rank
    ac自动机
    208. Implement Trie (Prefix Tree)
    php截取中文字符串 GB2312 utf-8
    纵向文字滚动代码,带上下图片控制的。鼠标放到上下图片上时滚动
    js图片切换 带左右控制的
    实时显示输入的内容
    Lightbox JS v2.0图片切换效果
  • 原文地址:https://www.cnblogs.com/softidea/p/5285935.html
Copyright © 2011-2022 走看看