• JDK1.7新特性(3):java语言动态性之脚本语言API


    简要描述:其实在jdk1.6中就引入了支持脚本语言的API。这使得java能够很轻松的调用其他脚本语言。具体API的使用参考下面的代码:

      1 package com.rampage.jdk7.chapter2;
      2 
      3 import java.io.FileWriter;
      4 import java.io.IOException;
      5 
      6 import javax.script.Bindings;
      7 import javax.script.Compilable;
      8 import javax.script.CompiledScript;
      9 import javax.script.Invocable;
     10 import javax.script.ScriptContext;
     11 import javax.script.ScriptEngine;
     12 import javax.script.ScriptEngineManager;
     13 import javax.script.ScriptException;
     14 import javax.script.SimpleBindings;
     15 
     16 /**
     17  * 简单的脚本引擎使用方法
     18  * 
     19  * @author zyq
     20  *
     21  */
     22 public class SimpleScriptAPI {
     23     public static void main(String[] args) throws ScriptException, IOException, NoSuchMethodException {
     24         SimpleScriptAPI simpleScriptEngine = new SimpleScriptAPI();
     25         
     26         // Part 1: 通用的脚本引擎用法
     27         ScriptEngine engine = simpleScriptEngine.getJavaScriptEngine();
     28         if (engine == null) {
     29             throw new RuntimeException("找不到JavaScript脚本执行引擎!");
     30         }
     31         engine.eval("var a = 12;");
     32         
     33         // Part 2: 不同脚本语言与java之间的对象绑定
     34         engine.put("name", "Alex");
     35         engine.eval("var message = 'hello ' + name");
     36         Object message = engine.get("message");
     37         System.out.println(message);         // hello Alex
     38         
     39         // 当然也可以通过SimpleBinds对象来进行变量绑定或者通过脚本引擎的createBindings方法
     40         Bindings bindings = new SimpleBindings();
     41         bindings = engine.createBindings();
     42         bindings.put("hobby1", "java");
     43         bindings.put("hobby2", "dota");
     44         engine.eval("var message2 = 'I like ' + hobby1 + ' and ' + hobby2", bindings);
     45         // 使用binding来绑定的变量只能在脚本语言内部是使用,java语言内获取不到对应的变量
     46         System.out.println(engine.get("message2"));        // null 
     47         System.out.println(engine.get("hobby1"));        // null
     48         System.out.println(engine.get("hobby2"));        // null
     49         engine.put("hobby1", "java");
     50         engine.put("hobby2", "dota");
     51         engine.eval("var message2 = 'I like ' + hobby1 + ' and ' + hobby2"); 
     52         System.out.println(engine.get("message2"));   // I like java and dota
     53         System.out.println(engine.get("hobby1"));      // java
     54         System.out.println(engine.get("hobby2"));      // dota
     55         
     56         // Part 3: 脚本执行上下文
     57         // ScriptContext的setReader/setWriter/setErrorWriter可以分别设置脚本执行时候的输入来源,输出目的地和错误输出目的地
     58         ScriptContext context = engine.getContext();
     59         context.setWriter(new FileWriter("output.txt"));
     60         engine.eval("var a = 13");
     61         // ScriptContext中也有setAttribute和getAttribute方法来自定义属性。属性有不同的作用域之分。
     62         // 每个作用域都以一个对应的整数表示其查找顺序,该整数越小,说明查找时的顺序更优先。
     63         // 因此在设置属性时需显示的指定所在的作用域,在获取属性的时候可以指定查找的作用域。也可以选择根据作用域优先级
     64         // 自动进行查找。
     65         // 但是脚本执行上下文所能包含的作用域可以通过 getScopes 方法得到而不能随意指定
     66         System.out.println(context.getScopes());        // [100, 200]
     67         // ScriptContext预先定义了两个作用域: ENGINE_SCOPE(当前脚本引擎) 和 GLOBAL_SCOPE(从同一引擎工厂创建出来的所有脚本引擎),前者的优先级更高
     68         context.setAttribute("name", "Alex", ScriptContext.GLOBAL_SCOPE);
     69         context.setAttribute("name", "Bob", ScriptContext.ENGINE_SCOPE);
     70         System.out.println(context.getAttribute("name"));        // Bob
     71         // ScriptContext的setbindings方法设置的语言绑定对象会影响到ScriptEngine在执行脚本时的变量解析。
     72         // ScriptEngine的put和get方法所操作的实际上就是ScriptContext中作用域为ENGINE_SCOPE的语言绑定对象。
     73         // 从ScriptContext中得到语言绑定对象之后,可以直接对这个对象进行操作。如果在ScriptEngine的eval中没有
     74         // 指明所使用的语言绑定对象,实际上起作用的是ScriptContext中作用域为ENGINE_SCOPE的语言绑定对象。
     75         Bindings binding1 = engine.createBindings();
     76         binding1.put("name", "Alex");
     77         context.setBindings(binding1, ScriptContext.GLOBAL_SCOPE);
     78         Bindings binding2 = engine.createBindings();
     79         binding2.put("name", "Bob2");
     80         context.setBindings(binding2, ScriptContext.ENGINE_SCOPE);
     81         System.out.println(engine.get("name"));        // Bob2
     82         Bindings binding3 = context.getBindings(ScriptContext.ENGINE_SCOPE);
     83         binding3.put("name", "Alex2");
     84         System.out.println(engine.get("name"));        // Alex2
     85         context.setAttribute("name", "Bob3", ScriptContext.ENGINE_SCOPE);
     86         System.out.println(engine.get("name"));        // Bob3
     87         
     88         // Part 4: 脚本的编译
     89         // 脚本语言一般是解释执行的,脚本引擎在运行时需要先解析脚本之后再执行。一般来说
     90         // 通过解释执行的方式运行脚本的速度比先编译再运行会慢一些。所以对于需要多次执行的脚本,我们
     91         // 可以选择先编译,以防止重复解析。不是所有的脚本语言都支持对脚本进行编译,如果脚本支持
     92         // 编译,他会实现 javax.script.Compilable接口。编译的结果用CompiledScript来表示。
     93         if (engine instanceof Compilable) {
     94             CompiledScript script  = ((Compilable) engine).compile("var a = 12; b = a * 3;");
     95             script.eval();
     96         }
     97         
     98         // Part 5: 方法调用
     99         // 有些脚本引擎允许使用者单独调用脚本中的某个方法。支持这种调用方法的脚本引擎可以实现
    100         // javax.script.Invocable 接口。通过Invocable接口既可以调用脚本中的顶层方法,也可一
    101         // 调用对象中的成员方法。如果脚本中的顶层方法或者对象中的成员方法实现了java中的接口,
    102         // 可以通过Invocable接口中的方法来获取及脚本中对应的java接口 的实现对象。这样就可以
    103         // 在java中定义借口,在脚本中实现接口。程序中使用该接口的其他部分代码并不知道接口是
    104         // 由脚本来实现的。
    105         String scriptText = "function greet(name) {return 'hello ' + name; }";
    106         engine.eval(scriptText);
    107         Invocable invocable = (Invocable) engine;
    108         System.out.println(invocable.invokeFunction("greet", "Alex"));  // hello Alex
    109         // 如果调用的是脚本中对象的成员方法,则需要用invokeMethod.
    110         scriptText = "var obj = {getGreeting: function(name) {return 'hello ' + name;}};";
    111         engine.eval(scriptText);
    112         Object scope = engine.get("obj");
    113         System.out.println(invocable.invokeMethod(scope, "getGreeting", "Bob"));  // hello Bob
    114         // 在脚本中实现接口
    115         scriptText = "function getGreeting(name) {return 'Hello ' + name;}";
    116         engine.eval(scriptText);
    117         Greet greet = invocable.getInterface(Greet.class);        // 接口必须是public类型的
    118         System.out.println(greet.getGreeting("KiDe"));
    119     }
    120 
    121     private ScriptEngine getJavaScriptEngine() {
    122         ScriptEngineManager manager = new ScriptEngineManager();
    123         // PS: 通过脚本引擎管理者来获取对应引擎,有三种方法:一是通过getEngineByName(这时只能是 javascript 或者
    124         // JavaScript)
    125         ScriptEngine engine = manager.getEngineByName("JavaScript");
    126         // 第二种方法是通过 getEngineByExtension (这时候只能是全小写的js)
    127         // engine = manager.getEngineByExtension("js");
    128         // 第三种方法是通过 getEngineByMimeType (这时候也必须是全小写的 text/javascript)
    129         // engine = manager.getEngineByMimeType("text/javascript");
    130         
    131         return engine;
    132     }
    133 }
    SimpleScriptAPI
    1 package com.rampage.jdk7.chapter2;
    2 
    3 public interface Greet {
    4     String getGreeting(String name);
    5 }
    Greet
  • 相关阅读:
    23种设计模式之单例模式
    Java基础之IO技术(一)
    spark利用yarn提交任务报:YARN application has exited unexpectedly with state UNDEFINED
    linux配置了dns后导致mysql远程连接慢问题
    发布网站后localhost可以访问ip不行
    electron编译sqlite3
    vscode文件树缩进
    js判断浏览器类型
    vue可复用slide动画
    vscode使用formate格式化less遇到的坑
  • 原文地址:https://www.cnblogs.com/Kidezyq/p/5754646.html
Copyright © 2020-2023  润新知