Java Script Engine
Java 腳本引擎可以將腳本嵌入Java代碼中,可以自定義和擴展Java應用程序,自JDK1.6被引入,基于Rhino引擎,JDK1.8后使用Nashorn引擎,支持ECMAScript 5,但后期還可能會換。
腳本引擎包位于javax.script中,各個類名及描述如下
接口
Bindings
鍵值對映射,所有key都為String
Compilable
由具體的腳本引擎實現,用于將腳本進行編譯,可重復使用。
Invocable 由具體的腳本引擎實現,其允許調用先前已執行的腳本
ScriptContext
腳本引擎上下文,用于將應用程序與腳本引擎進行綁定
ScriptEngine
由具體的腳本引擎實現,定義了執行腳本的方法、鍵值對映射關系、腳本引擎上下文
ScriptEngineFactory
腳本引擎工廠,每一個ScriptEngine都有一個對應的工廠。ScriptEngineManager會從ClassLoader中獲取所有的ScriptEngineFactories實例
類
AbstractScriptEngine
ScriptEngine的抽象實現類,提供了ScriptEngine的標準實現
CompiledScript
由存儲編譯結果的類擴展。可以以Java類、Java類文件或者腳本操作碼的形式存儲,可以重復執行無需重新解析。每個CompiledScript都與一個ScriptEngine相關聯,調用CompiledScript的eval方法會導致ScriptEngine執行
ScriptEngineManager
腳本引擎管理器,提供ScriptEngine的實例化機制,并維護了一些鍵/值對集合,供所有創建的ScriptEngine共享使用
SimpleBindings
使用HashMap 或者其他Map實現的一種簡單鍵值映射
SimpleScriptContext
ScriptContext 的一種簡單實現
異常
ScriptException
腳本API的通用異常類,拋出的異常類具有文件名、行號、列號信息
示例
簡單的
@Test
public void scriptTest() throws ScriptException {
ScriptEngineManager engineManager = new ScriptEngineManager();
//獲取JavaScript解析引擎
ScriptEngine engine = engineManager.getEngineByName("JavaScript");
//將x變量映射為Hello World!
engine.put("x", "Hello World!");
engine.eval("print(x)");
}
//輸出
//Hello World!
較復雜的
從文件中讀取腳本
/**
* 從文件中讀取Js腳本
* test.js 中的內容:
* var obj = new Object();
* obj.hello = function (name) {
* print('Hello, ' + name);
* }
* @throws Exception
*/
@Test
public void file() throws Exception{
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
engine.eval(new FileReader(new File("script/test.js")));
Invocable inv = (Invocable) engine;
Object obj = engine.get("obj");
inv.invokeMethod(obj, "hello", "Script Test!" );
}
將Java變量注入腳本中
有可能需要在腳本中使用Java變量
@Test
public void scriptVar() throws Exception{
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
File file = new File("F:/test/test.txt");
//將File對象f直接注入到js腳本中并可以作為全局變量使用
engine.put("files", file);
engine.eval("print(files.getPath());print(files.getName());");
}
調用腳本中的方法
使用Invocable 調用已經加載腳本中的方法
@Test
public void scriptTest1() throws ScriptException, NoSuchMethodException {
ScriptEngineManager engineManager = new ScriptEngineManager();
ScriptEngine engine = engineManager.getEngineByName("JavaScript");
StringBuilder sb = new StringBuilder();
sb.append("var obj = new Object();");
sb.append("obj.hello = function(name){print('Hello, ' + name);}");
engine.eval(sb.toString());
//Invocable 可以調用已經加載過的腳本
Invocable invocable = (Invocable) engine;
//獲取腳本的obj對象
Object object = engine.get("obj");
//調用obj對象的hello函數
invocable.invokeMethod(object, "hello", "Script Method!");
}
//輸出
//Hello, Script Method!
多個作用域
一個腳本引擎,多個scope,x變量并沒有覆蓋之前的變量
@Test
public void scriptTest() throws ScriptException {
ScriptEngineManager engineManager = new ScriptEngineManager();
ScriptEngine engine = engineManager.getEngineByName("JavaScript");
engine.put("x", "Hello World!");
engine.eval("print(x)");
ScriptContext context = new SimpleScriptContext();
//新的Script context綁定ScriptContext的ENGINE_SCOPE
Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
// 增加一個新變量到新的范圍 engineScope 中
bindings.put("x", "word hello!!");
// 執行同一個腳本 - 但這次傳入一個不同的script context
engine.eval("print(x);", bindings);
engine.eval("print(x);");
}
//輸出
//Hello World!
//word hello!!
//Hello World!
使用腳本實現Java接口
@Test
public void runnableImpl() throws Exception{
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
// String里定義一段JavaScript代碼腳本
String script = "function run() { print('run called'); }";
// 執行這個腳本
engine.eval(script);
// 從腳本引擎中獲取Runnable接口對象(實例). 該接口方法由具有相匹配名稱的腳本函數實現。
Invocable inv = (Invocable) engine;
// 在上面的腳本中,我們已經實現了Runnable接口的run()方法
Runnable runnable = inv.getInterface(Runnable.class);
// 啟動一個線程運行上面的實現了runnable接口的script腳本
Thread thread = new Thread(runnable);
thread.start();
Thread.sleep(1000);
}
如果腳本是基于對象的,則可以通過執行腳本的方法來實現Java接口,避免調用腳本的全局函數。
@Test
public void runnableObject() throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
String script = "var obj = new Object();obj.run = function() {println('run method called')}";
engine.eval(script);
//獲得腳本對象
Object object = engine.get("obj");
Invocable invocable = (Invocable) engine;
Runnable runnable = invocable.getInterface(object, Runnable.class);
Thread thread = new Thread(runnable);
thread.start();
Thread.sleep(1000);
}