Java通过ScriptEngine执行脚本语言
发表于|更新于
|字数总计:806|阅读时长:3分钟|阅读量:
前两天接到一个需求,大致归纳成以下三点:
- 要通过Java来解析并运行一段脚本
- 还不确定是什么语言的脚本
- 最终效果是Java把数据传进脚本里处理,处理完再接回来
看起来是不是很简单,但这做起来就不太顺手啊。
经过一番了解,在我在哪里可以找到可用的JSR-223脚本语言列表?这个帖子里找到相关的知识。
原来早在JDK1.6开始,Java就引入了JSR-223
规范,让我们通过脚本引擎这种统一接口的方式在JVM上运行脚本语言。
所以我最终选择了ScriptEngine
来完成这个需求,他本身仅支持JavaScript
,经过扩展后可支持Python
、Ruby
、Groovy
等。
直奔主题,敲代码!
编写逻辑操作类
这个类会被解析成脚本中对应的变量,可在脚本中调用类中的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class Codec { private final Sinks.Many<Context> processor = Sinks.many().multicast().onBackpressureBuffer(Integer.MAX_VALUE);
public Codec decoder(Function<Object, Context> function) { Context context = new Context(); function.apply(context); return this; }
public Codec handler(Context context) { processor.tryEmitNext(context); return this; }
public Flux<Context> handlePayload() { return processor.asFlux(); } }
|
编写上下文类
这里只有一个方法,用来测试对象传到脚本后,对象内的方法是否可以正常调用
1 2 3 4 5
| public class Context { public String getMessage(){ return "test msg"; } }
|
编写js脚本解析测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @Test public void jsEngine() throws ScriptException { String code = "codec.decoder(function (context) {\n" + " var message = context.getMessage();\n" + " codec.handler(context);\n" + " return {\n" + " messageType:\"REPORT_PROPERTY\"//消息类型\n" + " };\n" + "});"; ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript"); Compilable compilable = (Compilable) engine; CompiledScript compiledScript = compilable.compile(code); ScriptContext scriptContext = new SimpleScriptContext(); Codec codec = new Codec(); codec.handlePayload() .flatMap(context -> { System.out.println("message content: " + context.getMessage()); return Mono.empty(); }) .subscribe(); scriptContext.setAttribute("codec", codec, ScriptContext.ENGINE_SCOPE); compiledScript.eval(scriptContext); }
|
这个时候你就可以看到控制台打印出有message content: test msg
的字样,如果你不放心数据有没有经过脚本这一层,大可在脚本里再print
一次。
扩展其他语言的脚本
添加对应的Maven依赖
举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <dependency> <groupId>com.sun.script.jruby</groupId> <artifactId>jruby-engine</artifactId> <version>1.1.7</version> </dependency>
<dependency> <groupId>org.python</groupId> <artifactId>jython-standalone</artifactId> <version>2.7.0</version> </dependency>
<dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>3.0.7</version> </dependency>
|
查看是否扩展成功
再举个例子:
1 2 3 4 5 6 7 8 9 10 11 12
| @Test public void listEnginesName() { ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); List<ScriptEngineFactory> factories = scriptEngineManager.getEngineFactories(); for (ScriptEngineFactory factory : factories) { List<String> names = factory.getNames(); for (String name : names) { System.out.println(name); } System.out.println(factory.getEngineName() + " -> " + factory.getLanguageName()); } }
|
输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| nashorn Nashorn js JS JavaScript javascript ECMAScript ecmascript Oracle Nashorn -> ECMAScript groovy Groovy Groovy Scripting Engine -> Groovy jruby ruby JRuby Engine -> ruby python jython jython -> python
|