Java语⾔的动态性⽀持之ScriptEngineManager
⼀、脚本语⾔的⽀持
JSR 223中规范了在Java虚拟机上运⾏的脚本语⾔与Java程序之间的交互⽅式。JSR 233是JavaSE6的⼀部分,在Java表中API中的包是javax.script。⽬前Java虚拟机⽀持⽐较多的脚本语⾔,⽐较流⾏的有JavaScript、Scala、JRuby、Jython和Groovy等。
1. 脚本引擎
Java中执⾏脚本需要脚本语⾔对应的脚本引擎,JSR 223定义了脚本引擎的注册和查机制。JavaSE6中⾃带了JavaScript语⾔的脚本引擎,基于Mozilla的Rhino实现,可以通过三种⽅式查脚本引擎:
①通过脚本名称获取:
Java代码
1. ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
②通过⽂件扩展名获取:
Java代码
1. ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("js");
怎样让电脑定时关机③通过MIME类型来获取:
Java代码
1. ScriptEngine engine = new ScriptEngineManager().getEngineByMimeType("text/javascript");
如下代码,查注册JavaScript脚本引擎,打印"Hello!",JavaScript脚本中的println是Rhino引擎额外提供的⽅法。
Java代码
陶渊明诗1. public class BasicScripting {
2. public void greet() throws ScriptException {
3. ScriptEngineManager manager = new ScriptEngineManager();
4. ScriptEngine engine = EngineByName("JavaScript");
5. //ScriptEngine engine = EngineByExtension("js");
6. //ScriptEngine engine = EngineByMimeType("text/javascript");
7. if (engine == null) {
8. throw new RuntimeException("不到JavaScript语⾔执⾏引擎。");
9. }
10. engine.eval("println('Hello!');");
11. }
12.
13. public static void main(String[] args) {
14. try {
15. new BasicScripting().greet();
16. } catch (ScriptException ex) {
17. Logger(Name()).log(Level.SEVERE, null, ex);
18. }
19. }
20. }
2. 语⾔绑定
脚本语⾔⽀持API使⽤语⾔绑定对象实现Java语⾔编写的程序与脚本语⾔间的数据传递。语⾔绑定对象实际上就是⼀个简单的哈希表,⽤来存放和获取需要共享的数据,其定义的接⼝为javax.script.Bindings,继承⾃java.util.Map接⼝。⼀个脚本引擎在执⾏过程中可能会使⽤多个语⾔绑定对象,不同语⾔绑定对象的作⽤域不同。ScriptEngine类提供out和get⽅法对脚本引擎中特定作⽤域的默认语⾔绑定对象进⾏操作。
使⽤默认的语⾔绑定对象:
Java代码
1. public void useDefaultBinding() throws ScriptException {
2. ScriptEngine engine = getJavaScriptEngine();
3. engine.put("name", "Alex");
4. engine.eval("var message = 'Hello, ' + name;");
5. engine.eval("println(message);");
6. Object obj = ("message");
7. System.out.println(obj);
8. }
亦可以⾃定义语⾔绑定对象(如语⾔绑定对象中包含程序⾃⼰独有的数据等情形……):
Java代码
1. public void useCustomBinding() throws ScriptException {
2. ScriptEngine engine = getJavaScriptEngine();
3. Bindings bindings = new SimpleBindings();
4. bindings.put("hobby", "playing games");
5. engine.eval("println('I like ' + hobby);", bindings);
6. }
3. 脚本执⾏的上下⽂
脚本引擎通过执⾏过程中的上下⽂对象获取与脚本执⾏相关的信息,同时允许程序员通过此对象配置脚本引擎的⾏为。其上下⽂对象来⾃
javax.script.ScriptContext接⼝,类似于J2EE中javax.servlet.ServletContext接⼝,该接⼝主要包含3类信息:
①输⼊输出
默认情况下,脚本输⼊输出都是在标准控制台中,可以通过setReader和setWriter⽅法对输出流进⾏
重定向,可以通过setErrorWriter⽅法进⾏错误输出重定向。
Java代码
1. //例:将输出重定向到⽂件
2. public void scriptToFile() throws IOException, ScriptException {
3. ScriptEngine engine = getJavaScriptEngine();
4. ScriptContext context = Context();
5. context.setWriter(new FileWriter(""));
6. engine.eval("println('Hello World!');");
7. }
②⾃定义属性
上下⽂中通过setAttribute和getAttribute⽅法获取和设置属性,类似于ServletContext中设置和获取属
性操作。与ServletContext中不同的是,ScriptContext中的属性是有作⽤域之分的,ScriptContext按不同的顺序在不同的作⽤域中进⾏属性查(类似于JSP中EL表达式属性的作⽤域)。通过ScriptContext的getScopes可以得到其中所有可⽤的作⽤域,其中预定义了两个作⽤域:常量ScriptContext.ENGINE_SCOPE(当前的脚本引擎)和
ScriptContext.GLOBAL_SCOPE(从同⼀引擎⼯⼚中创建的所有脚本引擎对象)。
Java代码
1. public void scriptContextAttribute() {
2. ScriptEngine engine = getJavaScriptEngine();
3. ScriptContext context = Context();
4. context.setAttribute("name", "Alex", ScriptContext.GLOBAL_SCOPE);
5. context.setAttribute("name", "Bob", ScriptContext.ENGINE_SCOPE);
6. Attribute("name"); //值为Bob
ad钙奶
7. }
③语⾔绑定对象
语⾔绑定对象位于ScriptContext中,同样也有作⽤域之分,范围越⼩,优先级越⾼。执⾏如下代码,输出的name值为Bob。
中秋节的祝福1. public void scriptContextBindings() throws ScriptException {
2. ScriptEngine engine = getJavaScriptEngine();
3. ScriptContext context = Context();
4. Bindings bindings1 = ateBindings();
5. bindings1.put("name", "Alex");
6. context.setBindings(bindings1, ScriptContext.GLOBAL_SCOPE);
7. Bindings bindings2 = ateBindings();
8. bindings2.put("name", "Bob");
9. context.setBindings(bindings2, ScriptContext.ENGINE_SCOPE);
10. engine.eval("println(name);"); //Bob
11. }
也可以通过ScriptContext获取语⾔绑定对象:
Java代码
1. public void useScriptContextValues() throws ScriptException {
2. ScriptEngine engine = getJavaScriptEngine();
3. ScriptContext context = Context();
4. Bindings bindings = Bindings(ScriptContext.ENGINE_SCOPE);
5. bindings.put("name", "Alex");
适合雨天发的简短句子6. engine.eval("println(name);");
7. }
前⾯说到语⾔绑定对象存在于上下⽂环境中,故context中保存的⾃定义属性其实也是保存于语⾔绑定对象中的,如2中的语⾔绑定。
Java代码
1. public void attributeInBindings() throws ScriptException {
2. ScriptEngine engine = getJavaScriptEngine();
3. ScriptContext context = Context();
4. context.setAttribute("name", "Alex", ScriptContext.GLOBAL_SCOPE);
5. engine.eval("println(name);");
6. }
4. 脚本编译
脚本语⾔⼀般均是解释执⾏的,相对于编译执⾏的语⾔,效率较低⼀些。当脚本语⾔需要多次重复执⾏时,可以先对煎熬本进⾏编译,避免重复解析,提⾼效率(注:脚本编译需要脚本引擎⽀持,实现javax.script.Compilable接⼝)。JavaSE中⾃带的JavaScript引擎是⽀持对脚本进⾏编译的,编译的脚本⽤javax.script.CompiledScript来表⽰。
1. public class ScriptCompile extends JsScriptRunner {
2. //对脚本进⾏编译
3. public CompiledScript compile(String scriptText) throws ScriptException {
4. ScriptEngine engine = getJavaScriptEngine();
5. if (engine instanceof Compilable) {
6. CompiledScript script = ((Compilable) engine)pile(scriptText);
7. return script;
8. }
9. return null;
10. }
11.
12. //先编译再执⾏
13. public void run(String scriptText) throws ScriptException {
14. CompiledScript script = compile(scriptText);
15. if (script == null) {
16. return;
17. }
18. for (int i = 0; i < 100; i++) {
19. script.eval();
20. }
21. }
22.
23. public static void main(String[] args) {
24. ScriptCompile sc = new ScriptCompile();
25. try {
26. sc.run("println('Hello');");
27. } catch (ScriptException ex) {
28. Logger(Name()).log(Level.SEVERE, null, ex);
29. }
30. }
31. }
5. ⽅法调⽤
Java虚拟机⽀持脚本的意义在于实现函数式的编程,即脚本中最重要的便是⽅法。⼀些脚本引擎允许使⽤者单独调⽤脚本中的某个⽅法,⽀持此操作的脚本引擎可以通过实现javax.script.Invocable接⼝,⽀持顶层⽅法或者某对象中成员⽅法的调⽤。使⽤⽅法调⽤时最好先检查脚本引擎是否实现了Invocable接
⼝,JavaSE中的JavaScript引擎已实现了Invocable接⼝。
①在Java中调⽤脚本中的顶层⽅法
Java代码
1. public void invokeFunction() throws ScriptException, NoSuchMethodException {
2. ScriptEngine engine = getJavaScriptEngine();
3. String scriptText = "function greet(name) { println('Hello, ' + name); } ";
4. engine.eval(scriptText);
5. Invocable invocable = (Invocable) engine;
6. invocable.invokeFunction("greet", "Alex");
7. }
②调⽤脚本中某对象的成员⽅法
Java代码
1. public void invokeMethod() throws ScriptException, NoSuchMethodException {
2. ScriptEngine engine = getJavaScriptEngine();
3. String scriptText = "var obj = { getGreeting : function(name) { return 'Hello, ' + name; } }; ";
4. engine.eval(scriptText);
5. Invocable invocable = (Invocable) engine;小露珠像什么
6. Object scope = ("obj");
7. Object result = invocable.invokeMethod(scope, "getGreeting", "Alex"); //第⼀个参数为⽅法所属对象
8. System.out.println(result);
9. }
③指定脚本中的⽅法为Java接⼝的实现
Greet是Java实现的接⼝,包含⼀个⽅法getGreeting,通过Interface()⽅法指定脚本中的⽅法为Java接⼝的实现。
1. public void useInterface() throws ScriptException {
2. ScriptEngine engine = getJavaScriptEngine();
3. String scriptText = "function getGreeting(name) { return 'Hello, ' + name; } ";
4. engine.eval(scriptText);
5. Invocable invocable = (Invocable) engine;
6. Greet greet = Interface(Greet.class);
7. System.out.Greeting("Alex"));
8. }
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论