Java使⽤ScriptEngine动态执⾏代码(附Java⼏种动态执
⾏代码⽐较)
引⾔
在Java项⽬中,或多或少我们有动态执⾏代码的需求,⽐如:
系统中有⼀个规则验证需求,但规则经常改变
代码热更新,热修复
笔者也在⽬前参与的⼀个项⽬中遇到了动态执⾏代码的需求:项⽬需要⼀个⾃动审核模块,但是审核规则根据相关书⾯⽂件制定,如果写死在.java⽂件⾥,那么当新的书⾯⽂件下发时,就要系统停机更新系统,然后才能继续使⽤,其中存在着很多不稳定因素,也很⿇烦。因此在设计上就有动态执⾏代码的需求。好在这个需求只是审核⼀个表单,并没有对系统的操作和IO操作,输⼊参数也很固定。
笔者上⽹查阅了⼤量资料,发现⽹上⼤致流传三种动态执⾏代码⽅式,笔者经过全⾯⽐较,选择了其中⼀种。这⾥将⼏种⽅法列举如下。
⽅法
1.使⽤JEXL动态执⾏表达式
参考
JEXL⽀持两种循环⽅式:
for(item : list) {
x = x + item;
}
while (x lt 10) {
x = x + 2;
}
优点:可以动态执⾏Java代码,调⽤Java Function(Function需先传⼊JexlContext)
缺点:只能执⾏⼀个“表达式”,⽽不是Function,所以有很多语法局限,不是真正执⾏⼀个Function
2.使⽤Java动态编译
参考
动态编译⼀直是Java的梦想,从Java 6版本它开始⽀持动态编译了,可以在运⾏期直接编译.java⽂件,执⾏.class,并且能够获得相关的输⼊输出,甚⾄还能监听相关的事件。不过,我们最期望的还是给定⼀段代码,直接编译,然后运⾏,也就是空中编译执⾏(on-the-fly)。
优点:功能强⼤,能够真正实现完整的动态执⾏功能,能够动态调⽤全部系统功能和IO操作。
缺点:虽然功能强⼤,可以编译.java⽂件,但是还是很难在运⾏时替换框架级的类⽂件,但是相⽐于上述⽅法已
经有过之⽽⽆不及了;能动态调⽤全部系统功能和IO操作,与⼀般代码环境没有隔离,从⽽会成为项⽬中⼀个⾮常严重的安全隐患处。
3.使⽤Java ScriptEngine
使⽤Java⾃带的ScriptEngine可以说是最完美的Java动态执⾏代码⽅案之⼀(不考虑代码热更新等场景),关于ScriptEngine ⽹上有⼤量资料可供参考,这⾥就不附参考资料了,简单提供下⼀个使⽤JS Engine的例⼦:
String regular="function regular(args1,args2,args3){................}";
ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript");
try {
engine.eval(regular);
if (engine instanceof Invocable) {
Invocable invoke = (Invocable) engine;
String result = (String) invoke.invokeFunction(
"regular",
args1,
args2,
args3);
System.out.println(result);
} else {
System.out.println("error");
}
}
} catch (ScriptException e) {
System.out.println("表达式runtime错误:" + e.getMessage());
}
使⽤eval(),动态执⾏⼀遍JS代码(包含⼀个JS function),然后利⽤Java的Invoke传⼊参数,最后获取返回值。
优点:可以执⾏完整的JS⽅法,并且获取返回值;在虚拟的Context中执⾏,⽆法调⽤系统操作和IO操作,⾮常安全;可以有多种优化⽅式,可以预编译,编译后可以复⽤,效率接近原⽣Java;所有实现ScriptEngine接⼝的语⾔都可以使⽤,并不仅限于JS,如Groovy,Ruby等语⾔都可以动态执⾏。
缺点:⽆法调⽤系统和IO操作,也不能使⽤相关js库,只能使⽤js的标准语法。更新:可以使⽤scriptengine.put()将Java原⽣Object传⼊Context,从⽽拓展实现调⽤系统和IO等操作。
对于⼀般的动态执⾏代码需求,建议使⽤最后⼀种⽅法。
JDK8中Java调⽤Javascript脚本引擎动态定义与执⾏代码
import java.lang.*;
python转java代码import java.util.Arrays;
import java.util.List;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class ScriptEngineTest {
public static void main(String[] args) throws Exception {
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine engine = EngineByName("javascript");    //python or jython,
<pre name="code" class="html">  //向上下⽂中存⼊变量
engine.put("msg", "just a test");
//定义类user
String str = "msg += '';var user = {name:'tom',age:23,hobbies:['football','basketball']}; ";
engine.eval(str);
//从上下⽂引擎中取值
String msg = (String) ("msg");
String name = (String) ("name");
String[] hb = ("hb");
System.out.println(msg);
System.out.println(name + ":" + hb[0]);
//定义数学函数
engine.eval("function add (a, b) {c = a + b; return c; }");
//取得调⽤接⼝
Invocable jsInvoke = (Invocable) engine;
//定义加法函数
Object result1 = jsInvoke.invokeFunction("add", new Object[] { 10, 5 });
System.out.println(result1);
//调⽤加法函数,注意参数传递的⽅法
Adder adder = Interface(Adder.class);
int result2 = adder.add(10, 35);
System.out.println(result2);
//定义run()函数
engine.eval("function run() {print('www.java2s');}");
Invocable invokeEngine = (Invocable) engine;
Runnable runner = Interface(Runnable.class);
//定义线程运⾏之
Thread t = new Thread(runner);
t.start();
t.join();
//导⼊其他java包
String jsCode = "importPackage(java.util);
var list2 = Arrays.asList(['A', 'B', 'C']); ";
engine.eval(jsCode);
List<String> list2 = (List<String>) ("list2");
for (String val : list2) { System.out.println(val);}
}
}
脚本引擎为实现动态功能(如插件机制)提供了良好的扩展性.
有关引擎接⼝的⽂档:
到此这篇关于Java使⽤ScriptEngine动态执⾏代码(附Java⼏种动态执⾏代码⽐较)的⽂章就介绍到这了,更多相关Java ScriptEngine动态执⾏内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。