7.8 Node.js兼容框架
Limax集成原生java版本node.js兼容框架,使用JDK8提供的Nashorn引擎,依据node.js手册的描述实现,并做了适当扩展,以利于集成到Limax框架中,为连接Limax外的系统提供便利。
Nashorn支持ES5.1标准,对于某些ES6标准的js文件,应该首先使用6to5工具转换,现有Node.js手册示例都是ES6代码,应该转换以后实验。
以下的描述,符合node.js 6文档的顺序,便于对比。
-
7.8.1 核心模块
除了Buffer模块比较特殊, 放在包limax.node.js内, 其它核心模块均放置在包limax.node.js.modules内, 一个.java文件一个.js文件配对, 按照java习惯, 首字母大写, require时全小写。
-
Assert(断言)
功能与标准node.js一致。AssertionError类做了一些信息伪造。实际上,js中,Error类无法被有效继承,特别是在stack的问题上。
-
Buffer
不同于其它核心模块的对象, Buffer不是js对象, 直接导出了limax.node.js.Buffer对象。原因在于, node.js文档描述了[]操作, 但是ES5.1标准不支持索引化属性的访问, 所以使用了Nashorn的一个怪异特性, 实现了List接口的对象可以用[]方式问, 带来的问题是BoundCheck在Nashorn中完成, 数组越界会直接抛出异常, 这一行为与js不一致。 最好避免使用[]访问Buffer。
-
Java插件
不同于node.js用C++实现,使用C++创建插件。Limax的Node插件用Java创建,一个插件就是一个jar,一个插件jar内部只能有一个js文件,同时保证存在一个相应名字的java类,更多的细节可以参见limax.node.js.modules包。
例如:
MyTest.java
package testnodejsmodule; import limax.node.js.EventLoop; import limax.node.js.Module; public final class MyTest implements Module { public MyTest(EventLoop eventLoop) { } public Number add(Number x, Number y) { return x.doubleValue() + y.doubleValue(); } }
MyTest.js
exports.add = function(x, y) { return java.add(x, y); }
这样两个程序用eclipse export成一个jar,就可以作为插件被引用。
将插件命名为 test.jar 放置在主模块目录下,执行主模块
console.log(require('./test.jar').add(1,2))
即可输出结果3。
具体细节详见模块一节。
-
Child Processes(子进程)
使用java.lang.ProcessBuilder操控子进程,支持进程管道操作。
1. 不支持child_process.fork方法,Limax使用线程模型,不需要这个方法,详见模块一节。
2. 类ChildProcess仅支持exit事件(其它事件都与IPC相关, 不需要), 在进程结束后触发。支持child.kill方法, java.lang.Process向进程发送的信号仅支持SIGTERM与SIGKILL, 非SIGKILL的情形, 一律默认SIGTERM。支持child.stdin, child.stdout, child.stderr, child.stdio。
3. 所有方法的options参数中, 支持options.cwd, options.env(Node.js手册中声明spawn方法默认process.env, exec方法默认null, 实际测试exec默认值也是process.env, 所以默认process.env), options.shell, options.detached, options.input, options.timeout, options.encoding, options.maxBuffer, options.killSignal(SIGTERM|SIGKILL), options.stdio(只支持3个标准IO对象)。
4. child_process.spawnSync方法返回的对象,没有pid成员,因为java.lang.Process不提供。
-
Cluster(集群)
Node.js使用进程模型, 一个进程对应一个Javascript虚拟机, 为了使用cpu的多核特性, 所以提出了集群概念, fork出更多的虚拟机, 使用IPC进行协调。Limax中, 通过扩充require, 允许require传递参数, 允许require创建新的虚拟机实例,完全可以达成同样的目的,而且更节约资源。
具体细节详见模块一节。
-
CLI(命令行)
可以在shell中执行,这种情况下 java –jar limax.jar node <module> [args]
可以作为Limax服务加载,在服务xml配置中添加:
<NodeService module=module_path> <parameter value="0" /> 按参数数量,顺序排列 </NodeService>
一条NodeService element启动一个javascript虚拟机线程执行module。
-
Console(控制台)
1. console.dir 作为console.log的别名,不支持显示颜色之类的选项。
2. 内部使用java.lang.String.format方法格式化输出字符串, 格式参数与node.js使用的sprintf格式参数稍有差异, 应该注意。如果格式化失败, 按照普通字符串对待。
3. console.timeEnd,用WeakHashMap管理,不删除定时器也不会有泄漏。
-
Crypto(加密)
1. node.js使用openssl实现, limax中主要使用jce实现, 支持的算法集合稍有差异。getCiphers(), getCurves(), getHashes(), 三个方法可以用来获取具体支持的算法, 进行比较。
2. Cipher类没有提供AEAD的支持,因为AEAD的使用流程尚未确定。
3. limax.util.OpenSSLCompat提供了需要的openssl兼容性支持。jce只支持自己的keystore与PKCS11, PKCS12, 这里通过使用limax.codec.asn1包, 提供PEM格式的支持, 这两处代码, 其它地方可能有用。
-
Debugger(调试器)
Nashorn根本不会生成js字节码,而是直接生成java字节码,深度调试应该使用java的调试器。
-
DNS(域名服务器)
node.js使用libresolve实现,limax使用jndi实现,所以不提供libresolve规格的错误码。
特别注意,lookup方法的返回结果,node.js文档描述与实现不一致,文档描述是错误的。
-
Domain(域)
node.js文档申明该模块是废弃的,所以不提供。
-
Error(错误)
错误类由Narshorn提供,不需要提供。
需要注意的是, Limax环境下, 所有通过callback报告的错误, 可能是js的Error, 也可能是java的Exception, 并没有统一成Error, 因为Exception可以提供更丰富的栈信息, 例如:
function(err) { if (err) { if (err instanceof Error) { console.log(err.message, err.stack); } else { err.printStackTrace(); } return; } }
这样的处理,可以输出最完整的错误信息。
-