Java 调用 Lua
app发版成本高,覆盖速度慢,覆盖率页低。一些策略上的东西如果能够从服务端控制会方便一些。
所以考虑使用Lua这种嵌入式语言作为策略实现,Java则是宿主语言。
总体上看是一个模板方法模式。Lua提供模板方法,其中需要的一些具体实现则有宿主语言Java提供。
1. Luaj:Java与Lua的桥梁
能够作为Java与Lua进行通信的桥梁工具还有别的一些。
但是Luaj 是用纯Java实现,客户端容易加载。且目前还一直有更新和维护,相对感觉靠谱。
需要注意的是: 新版的LuaJ3.0是针对Lua5.2开发的,对Lua5.1会有不兼容的部分(例如module函数不能用了)
如果使用Lua5.1,则可以使用LuaJ2.0.3
2. 使用
2.1 java工程引用jse的jar包
这个简单,下载LuaJ2.0.3版,解压,加载lib/luaj-jse-2.0.3.jar
lib/里边还有个jme,这个是针对j2me环境的。
2.2 示例介绍
功能
实现一个生成时间相关的参数的功能
value = (int)(timestamp / 1000 ) ^ (int)(timestamp / 400)
^ 符号表示按位异或。
其中:
– 整个式子的计算流程由lua提供模板方法
– 除法后取整的功能由lua以module方式提供
– lua没有原生的位操作,所以这部分由java提供
– lua原生的os.time()依赖系统,于是timestamp方法由java提供,生成秒级时间戳
文件目录说明
1 2 3 4 5 6 7 8 9 10 11 |
. |-- lua | |-- gen.lua 主流程文件 | `-- tool | `-- div.lua 提供除法 `-- src |-- app | `-- Calc.java java的入口程序 `-- lualib `-- Math.java java提供的异或方法,和时间戳方法 |
2.3 具体实现
接下来就看4个文件的具体代码吧。请着重注意注释,要说的都在里边了
Calc.java:
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 |
package app; import org.luaj.vm2.LuaValue; import org.luaj.vm2.lib.jse.JsePlatform; public class Calc { public static void main(String[] args) { long key = getKey(); System.out.println(key); System.out.println(getKeyJava()); } public static long getKey() { //获取一个lua的运行环境,lua虚拟机应该就在这里了 //lua是个弱类型语言,在java里,所有从lua获得的,或者要传递给lua的,都是LuaValue对象 LuaValue _G = JsePlatform.standardGlobals(); //执行gen.lua脚本 //_G.get("dofile")获取dofile方法的对象 //get其实是获取table值的方法,dofile就是全局table的一个值 //对于Function类型的对象可以用call方法去调用,参数就是lua方法需要的参数,但是一定要转换成LuaValue类型 _G.get("dofile").call(LuaValue.valueOf("lua/gen.lua")); //上一句执行完以后,gen.lua中的genkey函数就在全局变量中了, //可以这样直接调用 LuaValue key = _G.get("genkey").call(); return key.checklong(); } //用java实现的,比较用 //value = (int)(timestamp / 1000 ) ^ (int)(timestamp / 400) public static long getKeyJava() { long tm = System.currentTimeMillis() / 1000; return (tm / 1000) ^ (tm / 400); } } |
Math.java
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 |
package lualib; import org.luaj.vm2.LuaValue; import org.luaj.vm2.lib.OneArgFunction; import org.luaj.vm2.lib.TwoArgFunction; import org.luaj.vm2.lib.ZeroArgFunction; //luaj提供了一些方法模板 ZeroArgFunction OneArgFunction等 //具体可以看那个详细介绍 public class Math extends OneArgFunction { //lua的方法都是闭包,在java中一定是用类对象与之对应的。 //于是call这个方法就是调用闭包使用所调用的方法,必须实现 public LuaValue call(LuaValue modname) { //这是类在lua里是一个模块,也就是个函数包,在lua里也就是一个table //table的每一个元素是一个函数(闭包而已) //这个lib就是一个table,用来存放各个lua模块方法 LuaValue lib = tableOf(); //设置timestamp方法 lib.set("timestamp", new lua_timestamp()); //设置异或方法 lib.set("bitxor", new lua_bitxor()); //这里不确定:env是该类的环境参数,暂时没研究这一句的作用,本例中不设置也没关系 //env.set(modname.checkjstring(), lib); return lib; } static class lua_timestamp extends ZeroArgFunction { public LuaValue call() { return LuaValue.valueOf(System.currentTimeMillis() / 1000); } } static class lua_bitxor extends TwoArgFunction { public LuaValue call(LuaValue a, LuaValue b) { //lua传进来参数都是LuaValue的,java使用的时候需要使用相应的check方法转为本地变量 long pa = a.checklong(); long pb = b.checklong(); long r = pa ^ pb; //返回的时候需要用valueOf方法转为LuaValue类型 return LuaValue.valueOf(r); } } } |
lua程序就简单多了
gen.lua
1 2 3 4 5 6 7 8 9 10 11 12 13 |
--注意查找目录是从工程的根目录开始的 div = require ("lua.tool.div") --引用java提供的方法,则直接写java的类名就好 jlib = require ("lualib.Math") -- 模板方法 function genkey() tm = jlib.timestamp() a = div.div(tm, 1000) b = div.div(tm, 400) r = jlib.bitxor(a, b) return r end |
div.lua
1 2 3 4 5 6 |
module(..., package.seeall) -- 这里也可以require java提供的模块,本例没用到 function div(a, b) return math.floor(a / b) end |
3.总结
总体上来说调用起来还算容易,只是文档有些缺乏。
如果要用Lua5.2则必须用LuaJ3.0。LuaJ3.0和2.0.3还是有一些不一样的,可以参考前文提到的详细介绍。
http://levelup.sinaapp.com/