皇冠现金app急需运用程序自个儿的语言绑定对象,它为脚本语言引擎提供了3个通用的与Java交互的接口

Java语言的动态性之脚本语言帮衬API

Nashorn 和 javax.script 包

Nashorn 并不是首先个在 Java 平台上运维的脚本语言。在Java 陆 就提供了
javax.script java
包,它为脚本语言引擎提供了一个通用的与Java交互的接口。
本条通用接口包括了脚本语言的基本概念,如脚本代码的举行和编写翻译。其余,引进了Java
和本子实体之间的申明绑定。最后,javax.script
包为调用提供了可选援救(那差别于执行,因为它同意从3个脚本语言的运营时导出中间代码,供
JVM 运转时采用)。
Rhino 作为2个实例语言,在 Java 八 中早就被移除,今后 Java
平台提供的私下认可的脚本提供为 Nashorn。

       随着Java平台的风靡,很多的脚本语言(scripting language)都得以运营在Java虚拟机啊上,其中相比盛行的有JavaScript、JRuby、Jython和Groovy等。相对Java语言来说,脚本语言由于其灵活性卓殊强,非凡适合在有些景况下选择,比如描述应用中复杂多变的业务逻辑,并在行使运维进程中进行动态修改;为利用提供一种世界特定语言(Domainspecific Language,DSL),供未有技术背景的普通用户使用;作为利用中相继零部件之间的“胶水”,神速开始展览零部件之间的重组;急迅支付出利用的原型系统,从而急速收获用户反馈,并拓展创新;帮忙开发职员火速编写测试用例等。等于这个情形,假诺运用java来支付则事倍功半。

介绍 javax.script 和 Nashorn 的使用

让大家看二个很简短的例子,怎么样行使 Nashorn 从 Java 中运作 JavaScript:

import javax.script.*;

ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");

try {
  e.eval("print('Hello World!');");
} catch (final ScriptException se) {
  // ...
}

那边的关键概念是ScriptEngine接口,是从ScriptEngineManager中取得的。
那提供了叁个空的剧本环境,大家能够经过eval() 方法添加JavaScript 代码。
Nashorn 引擎提供了3个十足的大局 JavaScript 对象,因而有着对eval()
的调用都将在同三个环境中执行。
那象征大家得以在本子引擎中展开1各种eval() 调用和营造 JavaScrip
的境况。 例如:

e.eval("i = 27;"); 
e.put("j", 15); 
e.eval("var z = i + j;"); 
System.out.println(((Number) e.get("z")).intValue()); // prints 42

注那里须要专注的三个标题是,直接从 Java
与剧本引擎交互,大家日常不会得到任何有关值的类型的信息。
Nashorn 对大多数 Java 类型保持格外严密的绑定,所以大家需求小心。 当处理
JavaScript 的中央项目时,在 Java 中不足为奇会转换来对应的包装类。
例如,假设大家将以下行代码添加到上贰个示范中:

System.out.println(e.get("z").getClass());

大家很简单地发现再次回到值是java.lang.Integer类型,大家稍作一下修改:

e.eval("i = 27.1;"); 
e.put("j", 15); 
e.eval("var z = i + j;"); 
System.out.println(e.get("z").getClass()); 

那么此时e.get(“z”)的重回值的类型
java.lang.Double,那标志了二种档次系统里头的区分。 在 JavaScript
的其余达成中,这几个都将被视为数字类型(因为 JavaScript 不定义整数类型)。
但是,Nashorn 特别意识到数码的实在类型。

注意:
当处理 JavaScript 时,Java 程序员必须有觉察地知道 Java 的静态类型和
JavaScript 类型的动态之间本质的分歧。 如果未有发现到那一点,bug
就很有相当大或许发生。

在我们的例证中,我们在 ScriptEngine 上运用 了get() 和 put() 方法。
这个形式允许大家在 Nashorn
引擎执行的本子的大局范围内平昔拿走和设置对象,而无需间接编写或评估
JavaScript 代码。

       对于这么些运转在Java虚拟机平台上的脚本语言来说,并不供给为他们准备额外的周转条件,直接复用已有的Java虚拟机环境即可。那就节省了在运维环境上所需的本钱投入。在行使开发中动用脚本语言,实际上是“多语言开发”的壹种很好的履行,即基于使用的须求和语言自个儿的特色来挑选最合适的变成语言,以高速高效地缓解使用中的某一有的题目。二种不一致语言完结的零部件组合起来,用Java编写宗旨工作逻辑,用Ruby来拓展数据处理。差异语言编写的代码能够同时运转的同四个Java虚拟机之上。这个脚本语言和Java语言之间的相互,是由脚本语言援助API来形成的。

javax.script API

让我们在这一片段中不难描述 javax.script API 中的壹些最首要的类和接口。
这几个只是在那之中相当的小的API(多少个接口,四个类和1个要命类),自从 Java 陆中引进以来从未改观。

  • ScriptEngineManager
    剧本帮衬的入口点。 它在此进度中维护可用脚本达成的列表。这是透过 Java
    的劳动提供程序编写制定落到实处的,那是1种十一分通用的办法来治本具有不一致的完结的阳台扩展。
    暗中同意情状下,唯一可用的台本扩大是Nashorn,尽管其余脚本环境(如Groovy
    或JRuby)也足以选用。
  • ScriptEngine
    以此类代表大家背负爱惜解释实施脚本环境的引擎。
  • Bindings
    此接口扩张Map接口,并提供字符串(变量或其余标志的名目)黄岩乱弹本对象时期的映射。
    Nashorn 使用它来兑现 ScriptObjectMirror 机制的互操作性。

在实践中,大多数应用程序处理由 ScriptEngine上 的不二等秘书籍(如eval(),get()
和put())提供的对峙不透明的接口,可是掌握这一个接口如何插入到全方位脚本 API
的机理如故很有至关重要。

一.脚本引擎

     
 1段脚本的实践须求由该脚本语言对应的剧本引擎来成功。贰个Java程序能够选用同时涵盖各类脚本语言的推行引擎,这统统由程序的须求来支配。程序中所用到的脚本语言,都亟待有照应的剧本引擎。JSENCORE23三中定义了剧本引擎的挂号和摸索体制。那对于脚本引擎的完结者来说,是索要精通的。而貌似的开发职员只必要理解哪些通过脚本引擎管理器来获得相应语言的剧本引擎,并不须要通晓脚本引擎的注册机制。Java
SE6中自带了JavaScript语言的台本引擎,是基于Mozilla的Rhino来完毕的。对于其余的脚本语言,则必要下载对应的本子引擎的库并放在程序的类路径中。一般假若放在类路径中中,脚本引擎就足以被应用程序发现并利用。
       
首先介绍脚本引擎的相似用法。首先创立3个本子引擎管理器javax.script.ScriptEngineManager对象,再经过管理器来询问所需的JavaScript脚本引擎,最后通过脚本引擎来施行JavaScript代码。

ScriptEngineManagerDemo

皇冠现金app 1

施行结果

皇冠现金app 2

     
 下面的代码中是经过脚本引擎的名字进行查找的。实际上,脚本引擎管理共帮忙三种检索脚本引擎的法子,分别通过名称、文件扩大名和MIME类型来成功。

二.语言绑定

     
 脚本语言援助API的二个一点都不小优势在于它规范了Java语言与脚本语言之间的交互格局,使Java语言编写的主次可以与剧本之间实行双向的艺术调用和数量传递。方法调用的不二等秘书诀会在稍后介绍。数据传递是通过语言绑定对象来形成的。所谓的绑定对象正是一个简易的哈希表,用来存放在和收获须要共享的多寡。全部数据都对应以此哈希表中的多个条条框框,是简简单单的名值对。接口javax.script.Bindings定义了语言绑定对象的接口,继承自java.util.Map接口。二个本子引擎在推行进程中恐怕会动用八个语言绑定对象。区别语言绑定对象的作用域区别。在暗中同意意况下,脚本引擎会提供八个语言绑定对象,用来存放在实践进度中产生全局对象等。ScriptEngine类提供了put和get方法对剧本引擎中一定功效域的暗许语言绑定对象开始展览操作。程序能够直接选拔那么些暗中同意的语言绑定对象,也能够行使本身的言语绑定对象。在脚本语言的执行进程中,能够将语言绑定对象看成是1个额外的变量映射表。在分析变量值的时候,语言绑定对象中的名称也会被考虑在内。脚本执行进程中产生的全局变量等内容,会出现在言语绑定对象中。通过那种办法就旗开马到了Java与脚本语言之间的双向数据传递。

本子引擎暗许的言语绑定对象的示范

    /**
    * 脚本引擎默认的语言绑定对象的示例
     */
    public static void useDefaultBinding(){
        try{
            ScriptEngine  engine = getJavaScriptEngine();
            engine.put("name","Arthur");
            engine.eval("var message = 'Hello,' + name;");
            engine.eval("print(message);");
            Object obj = engine.get("message");
            System.out.println(obj);
        }catch (Exception e){
            System.out.println("异常信息:"+e.getMessage());
        }
    }

本子引擎暗中认可的语言绑定对象的言传身教执行结果

皇冠现金app 3

    在多数景观下,使用ScriptEngine的put和get方法就丰裕了。假诺仅使用put和get方法,语言绑定对象自作者对于开发职员来说是晶莹剔透的。在有些情形下,要求使用程序自身的语言绑定对象,比如语言绑定对象中带有了先后本人独有的数额。如若愿意利用自身的言语绑定对象,能够调用脚本引擎的createBindings方法或创办,并传递给脚本引擎的eval方法。

自定义语言绑定对象的示范

    /**
     * 自定义语言绑定对象的示例
     */
    public static void userCustomBinding(){
        try{
            ScriptEngine engine = getJavaScriptEngine();
            Bindings bindings = new SimpleBindings();
            bindings.put("hobby","playe games");
            engine.eval("print('I like ' + hobby);",bindings);
        }catch(Exception e){
            System.out.println("异常信息:"+e.getMessage());
        }
    }

自定义语言绑定对象的言传身教的施行结果

皇冠现金app 4

    通过eval方法传递的语绑定对象,仅在时下eval调用中生效,并不会转移引擎暗中认可的言语绑定对象。

三.脚本实施上下文

    与剧本引擎执行相关的其余三个首要的接口是javax.script.ScriptContext,当中蕴藏脚本引擎执行进度的相干上下文音讯,能够通过与Java
EE中servlet规范中的javax.servlet.ServletContext接口来开始展览类比。脚本引擎通过此上下文对象得到与剧本执行相关的消息,也同意开发人士通过此指标来布署脚本引擎的一言一行。该上下文对象首要含有以下三类信息:

叁.1输入与输出

    首先介绍与脚本输入和输出的布局新闻,在那之中囊括脚本在推行中用来读取数据输入的java.io.Reader对象以及出口正确内容和失误新闻的java.io.Writer对象。在私下认可情状下,脚本的输入输出都在发生在行业内部部控制制弗罗茨瓦夫。

把脚本运维时的输出写入到文件中的示例

    /**
     * 把脚本运行时的输出写入到文件中。
     */
    public static void scriptToFile(){
        try {
            ScriptEngine engine = getJavaScriptEngine();
            ScriptContext context = engine.getContext();
            context.setWriter(new FileWriter("output.txt"));
            engine.eval("print('Hello World!');");
        } catch (ScriptException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

实施结果

皇冠现金app 5

说明
    通过setWriter方法把剧本的出口重定向到四个文本中。通过ScriptContext的set里德r和setErrorWriter方法能够分级设置脚本执行时的数额输入来源和产生错误时出错新闻的输出目标。

三.二自定义属性

    ScriptContext中也有与ServletConext中好像的得到和设置属性的办法,即setAttribute和getAttribute。所例外的是,ScriptContext中的属性是有成效域之分的。差异功用域的差异在于寻找属性时的顺序分裂。每一个功用域都以1个一见倾心的平头表示其搜索顺序。该整数值越小,表达查找时的逐一越优先。优先级高的功效域中的属性会暗藏优先级低的成效域中的同名属性。因而,设置属性时必要显式地内定所在地效率域。在收获属性地时候,既能够挑选在钦赐地功效域中搜索,也能够选取依据成效域优先级活动实行搜寻。
    但是脚本执行上下文实现中带有地成效域是永恒的,开发职员无法轻易定义本人的作用域。通过ScriptContext的getScopes方法能够博得全体可用的成效域列表。ScriptContext中优先定义了多少个功效域:

  • 常量ScriptContext.ENGINE_SCOPE代表的成效域对应的是当下的本子引擎。
  • 常量ScriptContext.GLOBAL_SCOPE表示的成效域对应的是从同一引擎工厂中创制出来的持有脚本引擎对象。

    说明: 前者的先期级较高

#### 作用域影响同名属性查找示例

       /**
     * 作用域影响同名属性查找的示例
     */
    public static void scriptContextAttribute(){
        try{
            ScriptEngine engine = getJavaScriptEngine();
            ScriptContext context = engine.getContext();
            context.setAttribute("name","Arthur Ming",ScriptContext.GLOBAL_SCOPE);
            context.setAttribute("name","明国宾",ScriptContext.ENGINE_SCOPE);
            System.out.println(context.getAttribute("name"));
            System.out.println(context.getAttribute("name",ScriptContext.GLOBAL_SCOPE));
        } catch(Exception e){
            System.out.println("异常信息:"+e.getMessage());
        }
    }

#### 执行结果

![](https://images2015.cnblogs.com/blog/1001991/201703/1001991-20170326223034830-213077996.png)

三.壹言语绑定对象

    脚本实施上下文中的尾声一类音信是语言绑定对象。语言绑定对象也是与效果域相对应的,同样的效能域优先级依次对语言绑定对象也适用。那样的预先级依次会对台本执行时的变量解析爆发震慑。

语言绑定对象的优先级依次的演示

    /**
     * 语言绑定对象的优先级顺序的示例
     */
    public static void scriptContextBindings(){
        try {
            ScriptEngine engine = getJavaScriptEngine();
            ScriptContext context = engine.getContext();
            Bindings binding1 = engine.createBindings();
            binding1.put("name","Arthur Ming");
            context.setBindings(binding1,ScriptContext.GLOBAL_SCOPE);
            Bindings binding2 = engine.createBindings();
            binding2.put("name","明国宾");
            context.setBindings(binding2,ScriptContext.ENGINE_SCOPE);
            engine.eval("print(name)");
        } catch (Exception e){
            e.printStackTrace();
        }
    }

施行结果

皇冠现金app 6

    通过ScriptContext的setBindings方法设置的语言绑定对象会影响到ScriptEngine在实践脚本时变量解析。ScriptEngine的put和get方法所操作的其实正是ScriptContext中的作用域为ENGINE_SCOPE的言语绑定对象。

透过脚本执行上下文获取语言绑定对象的演示

   /**
     * 通过脚本执行上下文获取语言绑定对象的示例
     */
    public static void useScriptContextValues(){
        try{
            ScriptEngine engine = getJavaScriptEngine();
            ScriptContext context = engine.getContext();
            Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
            bindings.put("name","Arthur Ming");
            engine.eval("print(name)");
        } catch (Exception e){
            e.printStackTrace();
        }
    }

执行结果

皇冠现金app 7

    自定义属性实际上也保留在言语绑定对象中。

自定义属性保存在语言绑定对象中示范

    /**
     * 自定义属性保存在语言绑定对象中示例
     */
    public static void attributeInBindings(){
        try{
            ScriptEngine engine = getJavaScriptEngine();
            ScriptContext context = engine.getContext();
            context.setAttribute("name1","Arthur Ming",ScriptContext.GLOBAL_SCOPE);
            context.setAttribute("name2","明国宾",ScriptContext.ENGINE_SCOPE);
            engine.eval("print(name1);");
            engine.eval("print(name2);");
        }catch (Exception e){
            e.printStackTrace();
        }
    }

执行结果

皇冠现金app 8