java 指令碼引擎
阿新 • • 發佈:2022-05-02
本文節選自《Netkiller Java 手札》
第 18 章 java 指令碼引擎
目錄
- 18.1. Maven
- 18.2. Helloworld
- 18.3. 執行指令碼檔案
- 18.4. 變數傳遞
- 18.5. 全域性變數與區域性變數定義
- 18.6. 呼叫指令碼中的函式或方法
- 18.7. 指令碼編譯
什麼是指令碼引擎,指令碼引擎是指在程式執行期間嵌入另一種指令碼語言,並與其互動,產生最終執行結果
指令碼引擎存在的意義是什麼?指令碼引擎可以改變編譯語言的內部執行邏輯,彌補編譯語言的不足,使編譯語言具備動態語言的一部分特性。
是否有成功案例?最成功的案例就是基於C++和Lua語言開發的端遊(網遊一種,需要按照客戶端),編譯語言最大的缺點就是客戶端升級需要重新安裝並且安裝之後重啟應用程式才能生效。指令碼引擎彌補了這項致命的缺點,使用者只需升級劇情指令碼,而不需要退出整個遊戲然後重新進入。
18.1. Maven
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.netkiller</groupId> <artifactId>script</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Java Script</name> <description>Java Script Engine</description> <dependencies> <!-- https://mvnrepository.com/artifact/org.mockito/mockito-all --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.10.19</version> </dependency> </dependencies> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
18.2. Helloworld
package javascript; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class Helloworld { public Helloworld() { ScriptEngineManager manager = new ScriptEngineManager(); List<ScriptEngineFactory> factories = manager.getEngineFactories(); for (ScriptEngineFactory f : factories) { System.out.println("egine name:" + f.getEngineName()); System.out.println("engine version:" + f.getEngineVersion()); System.out.println("language name:" + f.getLanguageName()); System.out.println("language version:" + f.getLanguageVersion()); System.out.println("names:" + f.getNames()); System.out.println("mime:" + f.getMimeTypes()); System.out.println("extension:" + f.getExtensions()); System.out.println("-----------------------------------------------"); } } public void hello() throws ScriptException { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("JavaScript"); // ScriptEngine engine = manager.getEngineByExtension("js"); // ScriptEngine engine = manager.getEngineByMimeType("text/javascript"); engine.eval("print('Hello, World')"); } public static void main(String[] args) { try { new Helloworld().hello(); } catch (ScriptException ex) { Logger.getLogger(Helloworld.class.getName()).log(Level.SEVERE, null, ex); } } }
18.3. 執行指令碼檔案
將指令碼放入外部檔案
package javascript;
import java.io.FileNotFoundException;
import java.net.URL;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class EvalFile {
public static void main(String[] args) {
// TODO Auto-generated method stub
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByExtension("js");
// ScriptEngine engine = manager.getEngineByMimeType("text/javascript");
try {
URL location = EvalFile.class.getProtectionDomain().getCodeSource().getLocation();
String file = location.getFile() + "test.js";
System.out.println(file);
engine.eval(new java.io.FileReader(file));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ScriptException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
test.js
print("This is hello from test.js");
18.4. 變數傳遞
package javascript;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
public class ScriptVars {
ScriptEngine engine = null;
public ScriptVars() {
ScriptEngineManager manager = new ScriptEngineManager();
engine = manager.getEngineByMimeType("text/javascript");
}
public void variable() throws ScriptException {
engine.put("name", "Neo");
engine.eval("var message = 'Hello, ' + name;");
engine.eval("print(message);");
Object obj = engine.get("message");
System.out.println(obj);
}
public void simpleBindings() throws ScriptException {
Bindings bindings = new SimpleBindings();
bindings.put("name", "Neo");
engine.eval("print('I am ' + name);", bindings);
}
public void function() throws ScriptException {
engine.put("a", 4);
engine.put("b", 6);
Object maxNum = engine.eval("function max_num(a,b){return (a>b)?a:b;}max_num(a,b);");
System.out.println("max_num:" + maxNum + ", (class = " + maxNum.getClass() + ")");
Map<String, Integer> m = new HashMap<String, Integer>();
m.put("c", 10);
engine.put("m", m);
engine.eval("var x= max_num(a,m.get('c'));");
System.out.println("max_num:" + engine.get("x"));
}
public void object() throws ScriptException {
File f = new File("test.txt");
// expose File object as variable to script
engine.put("file", f);
// evaluate a script string. The script accesses "file"
// variable and calls method on it
engine.eval("print(file.getAbsolutePath())");
}
public void outputToFile() throws IOException, ScriptException {
ScriptContext context = engine.getContext();
context.setWriter(new FileWriter("script.log"));
engine.eval("print('Hello World!');");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
ScriptVars sv = new ScriptVars();
sv.variable();
sv.simpleBindings();
sv.outputToFile();
sv.function();
sv.object();
sv.outputToFile();
} catch (ScriptException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
18.5. 全域性變數與區域性變數定義
ScriptContext.GLOBAL_SCOPE 作用於 ScriptEngineManager, ScriptContext.ENGINE_SCOPE 作用於 ScriptEngine
package javascript;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class ContextVariable {
public static void main(String[] args) throws ScriptException {
// TODO Auto-generated method stub
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
ScriptContext context = engine.getContext();
context.setAttribute("name", "Netkiller", ScriptContext.GLOBAL_SCOPE);
context.setAttribute("name", "Neo", ScriptContext.ENGINE_SCOPE);
//context.getAttribute("name");
engine.eval("print('I am ' + name);", context);
// engine1,context1 並沒有定義 name 但輸出結果卻顯示 Netkiller,所以ScriptContext.GLOBAL_SCOPE定義的變數是全域性的。
ScriptEngine engine1 = manager.getEngineByName("JavaScript");
ScriptContext context1 = engine1.getContext();
engine.eval("print('I am ' + name);", context1);
}
}
18.6. 呼叫指令碼中的函式或方法
package javascript;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class InvokeScriptFunction {
public static void main(String[] args) throws ScriptException, NoSuchMethodException {
// TODO Auto-generated method stub
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
// JavaScript code in a String
String script = "function hello(name) { print('Hello, ' + name); }";
// evaluate script
engine.eval(script);
// javax.script.Invocable is an optional interface.
// Check whether your script engine implements or not!
// Note that the JavaScript engine implements Invocable interface.
Invocable inv = (Invocable) engine;
// invoke the global function named "hello"
inv.invokeFunction("hello", "Scripting!!");
// JavaScript code in a String. This code defines a script object 'obj'
// with one method called 'hello'.
script = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }";
// evaluate script
engine.eval(script);
// get script object on which we want to call the method
Object obj = engine.get("obj");
// invoke the method named "hello" on the script object "obj"
inv.invokeMethod(obj, "hello", "Script Method !!");
}
}
18.7. 指令碼編譯
只有重複執行指令碼時才需要編譯。只執行一次不建議編譯執行。
package javascript;
import javax.script.*;
public class ScriptCompile {
public CompiledScript compile(String script) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
return ((Compilable) engine).compile(script);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ScriptCompile sc = new ScriptCompile();
try {
CompiledScript script = sc.compile("print('Helloworld!!!');");
for (int i = 0; i < 100; i++) {
script.eval();
}
} catch (ScriptException ex) {
ex.printStackTrace();
}
}
}