写点什么

Jvm 上如何运行其他语言?JSR223 规范最详细讲解

作者:架构师之道
  • 2022-12-07
    湖南
  • 本文字数:2038 字

    阅读完需:约 7 分钟

在 Java 的平台里,其实是可以执行其他的语言的。包括且不仅限于 jvm 发展出来的语言。

有的同学可能会说,在 java 项目里执行其他语言,这不吃饱了撑着么,java 体系那么庞大,各种工具一应俱全,放着好好的 java 不写,还要去执行其他语言干嘛。

写 java 的都知道,java 是需要事先编译的,这意味着你很难去在运行中改变编译好的 class 信息,除非你用字节码等技术栈,但是这也是需要很大的成本的。要想在运行中很方便的改变业务逻辑,其实用 java 去执行其他的脚本语言是一个好办法。况且有的脚本语言有着比 java 更简洁的语法特性。

有兴趣的小伙伴也可以看看之前的这篇文章:Java项目有可能做到所有的代码逻辑均可热部署吗?

在 java 中执行其他语言,可能你会觉得这应该很复杂,需要去学习每种语言包相关的 api。

笔者是开源框架 LiteFlow 的作者,在规则引擎 LiteFlow 中实践并支持了许多的其他语言,如 groovy,js,python,lua 等。

我可以负责任的说,在 Java 平台中调用其他脚本语言,其实一点都不复杂,你无需关心每种语言的实际 api。

这一切都归功于一个规范:JSR223

相信有大部分人没听过这个 Java 平台的规范。

JSR223 规范最初在 Java6 平台被提出,提供了一套标准的 API 为脚本语言的执行提供了内置支持。

也就是说,你只要熟悉这一套 API 就能执行大部分的脚本语言。

而且这套 API 的使用也是非常方便的,几个核心方法仔细看个 10 分钟就能明白如何使用。

来个最简单的例子:

//获得javascript的脚本引擎ScriptEngineManager scriptEngineManager = new ScriptEngineManager();ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("javascript");//进行脚本编译String script = "function process(){\n" +  "var a=10\n" +  "var b=3\n" +  "return a*b-c\n" +  "}\n" +  "process()";CompiledScript compiledScript = ((Compilable) scriptEngine).compile(script);//绑定java的参数Bindings bindings = new SimpleBindings();bindings.put("c", 5);//执行并打印结果Object result = compiledScript.eval(bindings);System.out.println(result);
复制代码

上述代码演示的是用 JSR223 API 去执行 javascript 语言。值得一提的是,java 内置了 javascript 引擎,你无需引入任何第三方包依赖就可以获得这个引擎。

整个过程分 4 块,分别是获得引擎,脚本编译,绑定 java 参数,执行。

在实际业务中,建议在系统启动的时候去编译脚本,然后把编译好的脚本对象compiledScript 对象给缓存起来,因为编译过程相对比较耗时,运行时每次去编译是个糟糕的设计。

如果在运行中改变了脚本,只需要重新去编译这个脚本并缓存其编译后的对象即可。

你只需要掌握以上代码,那几乎就已经掌握了 JSR223 规范的使用了。是不是很简单?

如果你想换成 groovy 脚本语言,那你需要依赖第三方依赖

<dependency>    <groupId>org.codehaus.groovy</groupId>    <artifactId>groovy-jsr223</artifactId>      <version>3.0.8</version></dependency>
复制代码

然后在上述的代码里获得引擎这块换成 groovy 即可:

...ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("groovy");...
复制代码

如果你想换成 python,需要依赖第三方依赖

<dependency>    <groupId>org.python</groupId>    <artifactId>jython-standalone</artifactId>      <version>2.7.3</version></dependency>
复制代码

然后在上述的代码里获得引擎这块换成 python 即可:

...ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("python");...
复制代码

看到这,是不是对利用JSR223规范如何执行脚本恍然大悟了呢。

其实现在很多的语言在 java 平台都推出了自己的 java 三方执行依赖包,而且很多的包都支持了 JSR223 规范。只要支持了 JSR223 规范的语言,都可以利用上述的代码来执行。

JSR223 规范的 API 可以支持 java 和其他语言的绑定和互通,一个 java 对象通过 bindings 对象也是可以传到脚本语言中的,在脚本语言中,你可以获得 java 的对象,来进行调用其方法和进行逻辑计算。

不过不同的语言调用操作符也许有所不同,比如 groovy,javascript 都是通过点操作符,和 java 很像,笔者在 LiteFlow 里新支持了 Lua 脚本,Lua 脚本的对 java 对象的操作符是冒号。所以当你的项目支持相关的脚本语言之前,你先要熟悉下相关语言的语法。

用脚本语言来担当 java 平台中经常需要变动的部分是一个不错的选择。关键原因是脚本语言的编译,执行完全是动态的,这意味着你可以在 java 运行中改变脚本,重新编译,并执行。利用此特性来进行变相的热部署。

LiteFlow 就是这样一款能够让你用多种脚本语言来定义你逻辑的规则引擎框架,这其中也利用了 JSR223 的规范 API,不仅能用脚本来编写逻辑,还能进行规则编排。

项目官网:

https://liteflow.yomahub.com

gitee 托管仓库:

https://gitee.com/dromara/liteFlow

希望大家都能从 JSR223 规范中找到一些设计你们相关业务系统的灵感。


来源:https://mp.weixin.qq.com/s/STTMnuplMRE8sxl-yR4-uQ

作者:铂赛东

用户头像

还未添加个人签名 2022-04-10 加入

还未添加个人简介

评论

发布
暂无评论
Jvm上如何运行其他语言?JSR223规范最详细讲解_Java_架构师之道_InfoQ写作社区