文章目录

  • Nashorn探索背景
  • Nashorn简介
  • Nashorn语法一览:
    • hello js in JVM
    • 在JVM在中调用js函数
    • 在js中调用java
  • 使用Nashorn的几种安全机制:
    • 使用ClassFilter限制js引擎可以访问的类
    • Nashorn沙箱
  • Nashorn沙箱的实现原理浅析:
  • 写在最后

Nashorn探索背景

通过合理的设计,将应用程序中所有动态变量都配置化,可以最大程度上让程序变得灵活。而灵活的配置,既可以减少开发成本,又能提高交付的效率。
提到业务规则的可配置化技术,自然是首推规则引擎了,像drools,easy rule 都是比较优秀的开源规则引擎,他们可以通过特定的语法,将if esle等判断逻辑从代码中独立出来,甚至可以热更新规则,非常的成熟好用。
只不过,有些时候,我们可能并不需要规则引擎的所有完整的功能,也不想引入一堆依赖的包,我们只是想要做一些简单的逻辑配置工作,这个时候,Nashorn脚本引擎就可以纳入考虑的范围了。

Nashorn简介

Nashorn 最初是在 JDK 8 中引入的,用于取代 Rhino 脚本引擎。当其发布时,Nashorn 是 ECMAScript-262 5.1 的完整实现,增强了 Java 和 JavaScript 的兼容性。
借助 Nashorn,开发人员可以从 JavaScript 调用 Java 代码,也可以从 Java 代码调用 JavaScript 函数。Nashorn 可以作为 Java 应用程序的嵌入式解释器,提供使用 Nashorn 命令行工具 jjs 从命令行运行 JavaScript 的能力。当在 Java 中对 JavaScript 代码求值时,Nashorn 实现了javax.script API。

Nashorn语法一览:

Nashorn使用的都是原生的java和js语法,并没有什么上手门槛,需要注意的是,js语法并不支持ES6。下面我们简单的看一下如何使用它。

hello js in JVM

Nashorn是JDK中自带的包,并不需要引入额外的依赖,只不过要jdk1.8的版本才支持。它通过在JVM上以原生方式运行动态JavaScript代码的方式来扩展java的功能。
首先,我们来感受一下在jvm运行js的骚操作:

 ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("nashorn");scriptEngine.eval("print('hello js in jvm')");

这里可以直接写js代码,也可以读取特定的文件中的js代码,也就是说,这里的js脚本,我们是可以在前端灵活配置的,这样就达到了我们随心所欲配置规则的目的了。

在JVM在中调用js函数

Nashorn支持调用js的函数,我们先在脚本中定义函数,再到JVM

var sayHi = function(name) {print('hello js,my name is  ' + name);return "result from js";
};

调用方法:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("script.js"));
Invocable invocable = (Invocable) engine;
Object result = invocable.invokeFunction("sayHi", "JAVA");
System.out.println(result);//此处为调用控制台返回值:
//hello js,my name is  JAVA
//result from js

在js中调用java

反过来,也可以在js中调用java的方法也很简单:
先定义静态方法

   static String sayHiByJava(String name) {System.out.format("hello java,my name is  %s", name);return "result from java";}

注意,调用时,需要先使用Java.type引入java class,类似于java中import

var MyJavaClass = Java.type('com.lx.soil.demos.leetcode.Solution');
var result = MyJavaClass.sayHiByJava('js');
print(result);//此处为调用控制台返回值:
//hello java,my name is  js
//result from java

使用Nashorn的几种安全机制:

既然是可以支持动态传入脚本来运行js代码,而且可以调用java中的类,那么安全问题就是我们所必须要注意的了,在安心使用Nashorn前,下面两个点是必须要解决的:

  1. 首先是防止任意代码执行的漏洞
  2. 防止代码有逻辑错误死循环导致占用大量资源

好在,现在有两个比较靠谱的方案来解决这些问题:

使用ClassFilter限制js引擎可以访问的类

1.在jdk1.8中引入了ClassFilter来限制可以访问的类,只要限制了可以访问的类,那么代码任意执行的漏洞就可以解决了,但是这个还不完美,因为还有第二个问题没解决。

import javax.script.ScriptEngine;
import jdk.nashorn.api.scripting.ClassFilter;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;public class MyClassFilterTest {class MyCF implements ClassFilter {@Overridepublic boolean exposeToScripts(String s) {if (s.compareTo("java.io.File") == 0) return false;return true;}}public void testClassFilter() {final String script ="print(java.lang.System.getProperty(\"java.home\"));" +"print(\"Create file variable\");" +"var File = Java.type(\"java.io.File\");";NashornScriptEngineFactory factory = new NashornScriptEngineFactory();ScriptEngine engine = factory.getScriptEngine(new MyClassFilterTest.MyCF());try {engine.eval(script);} catch (Exception e) {System.out.println("Exception caught: " + e.toString());}}public static void main(String[] args) {MyClassFilterTest myApp = new MyClassFilterTest();myApp.testClassFilter();}
}

执行完则会报错:

C:\Java\jre8
Create file variable
Exception caught: java.lang.RuntimeException: java.lang.ClassNotFoundException:
java.io.File

Nashorn沙箱

事实上,Nashorn本身就考虑了安全问题,实现了一套沙箱机制(SandBox),用法如下:

NashornSandbox sandbox = NashornSandboxes.create();
sandbox.allow(File.class);
sandbox.eval("var File = Java.type('java.io.File'); File;")

限制nashorn引擎的资源使用也有考虑:

NashornSandbox sandbox = NashornSandboxes.create();
sandbox.setMaxCPUTime(100);
sandbox.setMaxMemory(50*1024);
sandbox.allowNoBraces(false);
sandbox.setMaxPreparedStatements(30); // because preparing scripts for execution is expensive
sandbox.setExecutor(Executors.newSingleThreadExecutor());
sandbox.eval("var o={}, i=0; while (true) {o[i++]='abc';};");

Nashorn沙箱的实现原理浅析:

java应用程序本身就是自带沙箱的,只不过一般都没有被启用,要启用沙箱,在启动的命令行要加如下参数:

java -Djava.security.manager <other args>

沙箱启动后,安全管理器会使用两个默认的策略文件来确定沙箱启动参数。当然也可以通过命令指定:

java -Djava.security.policy=<URL>

如果要求启动时只遵循一个策略文件,那么启动参数要加个等号,如下:

java -Djava.security.policy==<URL>

关于java的安全沙箱,这里有一篇比较完整的介绍文章,有兴趣的同学可以看看。
java安全沙箱

写在最后

本来Nashorn是有计划支持ES6的,但是由于对ES6的支持太过困难,导致oracle放弃了这一想法(手动表示遗憾。。。),甚至打算弃用Nashorn,所以最后在我的项目中并没有使用Nashorn引擎,而是选用了抽象的方式去迂回实现我所需要的功能,但是,Nashorn确实给我提供了一种思路,一种能让我在终极可配置化的道路上走的更远的思路,一种能让我离"write once, run forevre"的终极目标更近一小步的思路。

by: eric02.li

初探Java Nashorn脚本引擎相关推荐

  1. Java 8 的 Nashorn 脚本引擎教程

    本文为了解所有关于 Nashorn JavaScript 引擎易于理解的代码例子. Nashorn JavaScript 引擎是Java SE 8的一部分,它与其它像Google V8 (它是Goog ...

  2. nashorn java_Java 8: Nashorn脚本引擎使用

    使用Nashorn Nashorn javascript 引擎要么在java程序中以编程的方式使用要么在命令行工具jjs使用,jjs在目录$JAVA_HOME/bin中.如果你准备建立一个jjs的符号 ...

  3. jsr223 java_JSR223 Java使用脚本引擎动态修改业务逻辑

    本文来自图灵社区 @fairjm 转截请注明出处 偶尔会有一些业务需求是需要在动态改变线上代码的行为.一般的做法是使用个配置文件,存在数据库或者redis等存储中,程序动态获取之后解析并根据配置进行相 ...

  4. 【Java脚本引擎】脚本引擎执行JavaScript代码

    应用场景 公司有30员工,每个人工资计算方式不同.现在需要计算工资. 传统的方法:一个接口,30个实现类. 使用脚本引擎:编写一个xml文件,每人一个计算公式,使用的时候可以把公式加载到程序中,启动时 ...

  5. Java8 新JavaScript脚本引擎Nashorn小试

    一个对Nashorn脚本引擎很详细地介绍: http://winterbe.com/posts/2014/04/05/java8-nashorn-tutorial/ 下面是我测试的小例子,模拟在游戏中 ...

  6. Java 脚本引擎的使用

    文章目录 1. 前言 2. 脚本引擎的使用 2.1 脚本参数传递 2.2 脚本编译 2.3 脚本动态调用 1. 前言 Java 6 版本就已经引入了 Rhino 引擎用以支持脚本代码运行,而从 Jav ...

  7. 1.11. java 脚本引擎

    什么是脚本引擎,脚本引擎是指在程序运行期间嵌入另一种脚本语言,并与其交互,产生最终运行结果 脚本引擎存在的意义是什么?脚本引擎可以改变编译语言的内部运行逻辑,弥补编译语言的不足,使编译语言具备动态语言 ...

  8. java js引擎,Java8 Nashorn JavaScript引擎

    使用Java8,Nashorn大大提高了JavaScript 引擎引入,以取代现有的Nashorn Java脚本引擎.Nashorn提供2至10倍更好的性能,因为它直接编译代码在存储器,并传递到字节码 ...

  9. java引擎组件_Java 脚本引擎入门

    Java Script Engine Java 脚本引擎可以将脚本嵌入Java代码中,可以自定义和扩展Java应用程序,自JDK1.6被引入,基于Rhino引擎,JDK1.8后使用Nashorn引擎, ...

最新文章

  1. 预测 motif 的计算原理
  2. 跨域以及一些解决方法
  3. 内网穿透和内网映射区别是什么?
  4. 二分查找递归与非递归的时间比较_我们说一说Python的查找算法!
  5. es5直接引入html文件,ES6+转ES5(webpack+babel、指定多个js文件、自动注入)
  6. MYSQL数据库学习----查询
  7. java中的异常处理代码,java_深入剖析Java中的各种异常处理方式,1. 调试追踪代码:public s - phpStudy...
  8. HTML5定稿了,终于有一种编程语言开发的程序可以在Android和IOS两种设备上运行了...
  9. TCA9548A IIC多路扩展模块使用
  10. 百度地图实现定位图标随手机方向变化而变化,即运用方向传感器
  11. Mac在已安装Python3.9的情况下利用miniconda配置【Python3.7+TensorFlow1.14环境】+ Sublime Text如何通过conda切换不同Python环境
  12. Mac 重启后,连接不上wifi
  13. 《魔兽争霸》故事背景
  14. 几种实现数据扁平化的方法
  15. Python爬虫——selenium爬取网易云评论并做词云
  16. CMDN创新应用:果库 - 帮助你发现喜欢的商品
  17. 铁威马远程samba服务器稳定,NAS网络存储的Samba访问
  18. CSU-ACM2019寒假训练1-E - 可能简单题
  19. 关于组长/leader的一些反省和自我批判
  20. PlusFo小道消息独家报道,与黑子的争霸谁能更胜一筹

热门文章

  1. [苹果APP上架]ios App Store上架详细教程-一条龙顺滑上架-适合小白
  2. 游戏建模:学习3Dmax心路历程感悟以及总结,不建议使用汉化版
  3. git 安装配置(windows环境)
  4. 法律网推荐(二) 用Pig进行数据预处理
  5. python raise 异常
  6. 听课记录高中计算机,高中听课记录.doc
  7. 白帽子黑客与网络安全工程师教你:如何使用DMitry域名查询工具技巧?
  8. oracle正则表达式匹配中文
  9. Matlab光标在线上移动,vi光标移动及常用指令
  10. c语言骑士游历优化算法,骑士游历问题(C语言代码)