初识ScriptEngine

想象一下这样的场景:有一个业务,需要设计一个黑盒系统,可以针对不同的输入参数,动态采取不同的策略及措施和输出,比如平台活动等场景。可能大家会想到的是规则,不同的规则场景下执行不同的一套java代码,也许是个好办法,但该办法可能不能简单的应对产品的热部署。

那我们换一个思路,是不是可以把那段实际经常发生变动的java代码分离出来呢,答案当然是肯定的。

方式一:通过字节码的机制,动态加载新的规则执行类class,也就是之前所说的有点麻烦的但可以解决热部署问题的方案。本文不做过多的探讨

方式二:再换个思路,索性连java代码都换掉,采用更加轻量的脚本语言,来执行我们需要的规则相应逻辑(毕竟我们的目标是完成一件事情,而不是限定某种语言或者某种方式的情况下去完成同样的事情,有时候往往太多的约束并不见得是好事)。值得庆幸的是,jdk在1.6之后,引入了ScriptEngine,提供了java环境中对脚本的调用,详细了解可以自行搜索jsr223规范,可惜的是目前只有个js引擎在jdk中有实现。其他的脚本引擎实现具体以spi的方式,由第三方来实现,比如大名鼎鼎的groovy脚本等。

其实脚本引擎做的事情及时方式一的变形,将对应的脚本进行词法语法的解析,生成javaclass最终在jvm里执行真正的调度。

简单说说ScriptEngine吧:

这是官方的顶定义:ScriptEngine is the fundamental interface whose methods must be  fully functional in every implementation of this specification. These methods provide basic scripting functionality.  Applications written to this  simple interface are expected to work with minimal modifications in every implementation.  It includes methods that execute scripts, and ones that set and get values. 

The values are key/value pairs of two types.  

The first type of pairs consists of  those whose keys are reserved and defined in this specification or  by individual  implementations.  The values in the pairs with reserved keys have specified meanings. 

The other type of pairs consists of those that create Java language Bindings, the values are  usually represented in scripts by the corresponding keys or by decorated forms of them.

简单的说,脚本引擎被设计成这样一个功能接口:数据交换和脚本执行

数据交换表现在调度引擎的时候,允许将数据输入/输出引擎,至于引擎内的数据持有具体方式嘛定义里提到了两种:1.普通的键值对;2.Bindings (interface Bindings extends Map<String,Object>)看到这个应该就能明白

引擎执行嘛,表现为eval(),当然有好多重载,无非就是多种脚本内容载入的输入源换一下,是否有额外数据传入等

其他几个重要的类:

ScriptEngineManager 顾名思义一个脚本引擎的管理类,用来创建脚本引擎,大概的方式就是在类加载的时候通过spi的方式,扫描classpath中已经包含实现的所有ScriptEngineFactory,载入后用来负责生成具体的ScriptEngine.具体有个initEngines方法可以关注一下,通过ServiceLoader来实现spi方式的加载。听说jdbc现在也这么玩了,不过还没实际考证过,有兴趣的小伙伴可以探究探究。

ScriptContext 顾名思义一个脚本引擎执行的上下文,接口中设计了两个scope,分别是ENGINE_SCOPE和GLOBAL_SCOPE其中GLOBAL_SCOPE的信息对相应的ScriptEngineFactory可见,除了这两个scope当然在脚本执行的时候还有私有的一个scope,大概有点像局部变量。

NashornScriptEngine jdk8中对ScriptEngine的一个实现,真正具有执行脚本能力的实现类。

Parse 用来解析脚本的类,具体参考parse()方法,有点语法树的味道

……

稍微带几句ScriptEngine用途:

1.首要的必然是执行脚本,两种方式一次性的解释执行以及编译后的反复执行

2.根据js引擎的一些投机取巧,可以判定一些表达式是否合法(当且仅当你没时间或者不想写一个验证类的时候,杀鸡用下牛刀):

比如eval("23 & 4!");  eval("2 | 3 & (5 & 4)")等逻辑表达式的检查,其中有两点要注意的是,jdk默认提供的脚本引擎并不保证线程的安全性,engineFactory.getParameter("THREADING")可以获得描述,具体好像是null,groovy等工厂返回的好像是MULTITHREADED

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351

推荐阅读更多精彩内容