澳门新葡萄京官网注册Java 脚本化编程指南

Java脚本化API为哪个人考虑?

脚本语言的局地卓有功效的性子是:

  • 有扶助:大繁多脚本语言都是动态类型的。您日常能够创设新的变量,而不表明变量类型,而且您能够选择变量来存款和储蓄不一样门类的对象。别的,脚本语言往往会活动实施大多项指标调换,举例,
    供给时 将数字10转移为“10”。
  • 开荒火速原型:您能够免止编写制确定人员编制写翻译运转周期,只使用“编辑运转”!
  • 使用扩充/定制:你能够“具体化”的有的应用程序,举个例子有个别布署脚本,业务逻辑/准绳和财务应用中的数学表明式
  • 为运用增多命令行格局,用于调试、运营时计划/布置时间。未来繁多应用程序都有叁个基于Web的GUI配置工具。不过系统管理员/计划人士经常向往命令行工具。二个“标准”的脚本语言能够用来落到实处这么些目标,而不是注解特设的脚本语言。

Java 脚本 API 是一种独立于框架的脚本语言,使用来源于Java代码的脚本引擎
。通过java脚本API,能够选择Java语言编写定制/可扩张的应用程序并将自定义脚本语言选择留下最后用户。Java 应用程序开拓者不须要在开拓进程中筛选扩充语言。若是您使用JSEnclave-223
API来编排应用,那么你的客商能够运用别的JSKoleos-223合作的脚本语言。

Nashorn 和 javax.script 包

Nashorn 实际不是第贰个在 Java 平台上运营的脚本语言。在Java 6 就提供了
javax.script java
包,它为脚本语言引擎提供了贰个通用的与Java交互作用的接口。
本条通用接口满含了脚本语言的基本概念,如脚本代码的实施和编写翻译。其它,引进了Java
和本子实体之间的表明绑定。最后,javax.script
包为调用提供了可选扶持(那不一致于实行,因为它同意从三个脚本语言的运行时导出中间代码,供
JVM 运行时行使)。
Rhino 作为一个实例语言,在 Java 8 中早已被移除,今后 Java
平台提供的暗中认可的本子提供为 Nashorn。

脚本包

Java 脚本功效是在 javax.script
包中。那是四个相当的小的,轻松的API。脚本的视角是 ScriptEngineManager
类。三个 ScriptEngineManager
对象能够通过jar文件的服务意识体制开掘脚本引擎。它也足以实例化脚本引擎来评释使用一定的脚本语言编写的本子。使用脚本编制程序接口的最简易的方法如下:

  1. 创立叁个 ScriptEngineManager  对象
  2. 从 ScriptEngineManager  获取 ScriptEngine  对象
  3. 使用 ScriptEngine的eval方法执行脚本

近年来,是时候看有的样品代码了。领悟一些JavaScript有助于阅读这一个事例,但不是抑遏的。

介绍 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 引擎提供了三个单纯的大局 JavaScript 对象,由此具备对eval(卡塔尔的调用都将在同一个遭受中实行。
那代表大家得以在剧本引擎中开展一文山会海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 代码。

实例

javax.script API

让大家在此一有些中轻巧描述 javax.script API 中的一些最首要的类和接口。
那些只是此中一点都不大的API(多少个接口,三个类和叁个充裕类),自从 Java 6
中引进以来从未退换。

  • ScriptEngineManager
    剧本帮忙的入口点。 它在这里进度中保养可用脚本完结的列表。那是透过 Java
    的服务提供程序编写制定落到实处的,那是一种特别通用的格局来保管具备不相同的兑现的阳台扩充。
    暗许景况下,独一可用的本子扩充是Nashorn,即便别的脚本情状(如Groovy
    或JRuby)也能够运用。
  • ScriptEngine
    那么些类代表大家背负维护解释实践脚本遇到的蒸汽轮机。
  • Bindings
    此接口扩张Map接口,并提供字符串(变量或其余标记的称谓)和本子对象之间的炫彩。
    纳什orn 使用它来兑现 ScriptObjectMirror 机制的互操作性。

在试行中,大许多应用程序管理由 ScriptEngine上 的艺术(如eval(State of Qatar,get()和put(卡塔尔国)提供的对峙不透明的接口,但是明白那些接口怎么样插入到全体脚本 API
的机理如故很有不可缺乏。

“Hello,World”

从ScriptEngineManager实例中,我们经过 getEngineByName 方法获得一个JavaScript引擎实例。通过脚本引擎的eval方法来施行给定的JavaScript代码。为方便起见,本例以致随后的例证中,大家不对相当举办拍卖。javax.script
API有自己斟酌和平运动行时十一分,你必需稳妥管理万分。

import javax.script.*;
public class EvalScript {
    public static void main(String[] args) throws Exception {
        // create a script engine manager
        ScriptEngineManager factory = new ScriptEngineManager();
        // create a JavaScript engine
        ScriptEngine engine = factory.getEngineByName("JavaScript");
        // evaluate JavaScript code from String
        engine.eval("print('Hello, World')");
    }
}

实行贰个本子文件

在这里个例子中,大家调用eval方法来采取java.io.Reader作为输入源。读入的脚本被奉行。这种措施可以成文件实践脚本,用相关的输入流对象读取ULANDL和能源。

import javax.script.*;
public class EvalFile {
    public static void main(String[] args) throws Exception {
        // create a script engine manager
        ScriptEngineManager factory = new ScriptEngineManager();
        // create JavaScript engine
        ScriptEngine engine = factory.getEngineByName("JavaScript");
        // evaluate JavaScript code from given file - specified by first argument
        engine.eval(new java.io.FileReader(args[0]));
    }
}

只要大家有叁个叫”test.js”的文书,里面包车型大巴剧情如下:

println("This is hello from test.js");

咱俩能够使用下边的方式来运作刚刚的台本

java EvalFile test.js

本子变量

当你的java应用程序嵌入脚本引擎和本子,你恐怕希望将你的应用程序对象为全局变量暴光于脚本中。那一个例子演示了怎么将你的应用程序对象作为全局变量暴光于脚本中。大家在应用程序中成立三个 java.io.File对象作为全局变量,名称是file。该脚本能够访谈变量,举例,它能够调用它的公家措施。注意访谈java对象、领域和措施的语法信任于脚本语言。JavaScript扶助最“自然”的好像java的语法。

public class ScriptVars { 
    public static void main(String[] args) throws Exception {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");

        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())");
    }
}

调用脚本函数和章程

微微时候,你只怕供给一再调用多少个一定脚本函数,比如你的应用程序菜单功效也许由脚本来达成。在菜单中的操作事件管理程序中,只怕要求调用叁个一定的本子函数。上面包车型地铁演示演示在Java代码调用一个特定的剧本。

import javax.script.*;

public class InvokeScriptFunction {
    public static void main(String[] args) throws Exception {
        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卡塔尔国或面向对象的,你能够在剧本对象上调用脚本方法。

import javax.script.*;

public class InvokeScriptMethod {
    public static void main(String[] args) throws Exception {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");

        // JavaScript code in a String. This code defines a script object 'obj'
        // with one method called 'hello'. 
        String script = "var obj = new Object(); obj.hello = function(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;

        // 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 !!" );
    }
}

经过脚本达成Java接口

有些时候经过脚本函数可能措施能够很方便的贯彻java接口,并非在Java中调用。同有时间,通过接口我们得以免止在不菲地点选取javax.script
API接口。大家可以取得二个接口完毕者对象并将其传递给分化的Java
api。下边包车型客车例证演示了通过脚本实现 java.lang.Runnable接口。

import javax.script.*;

public class RunnableImpl {
    public static void main(String[] args) throws Exception {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");

        // JavaScript code in a String
        String script = "function run() { println('run called'); }";

        // evaluate script
        engine.eval(script);

        Invocable inv = (Invocable) engine;

        // get Runnable interface object from engine. This interface methods
        // are implemented by script functions with the matching name.
        Runnable r = inv.getInterface(Runnable.class);

        // start a new thread that runs the script implemented
        // runnable interface
        Thread th = new Thread(r);
        th.start();
    }
}

假诺您的脚本语言是基于对象恐怕面向对象的,能够因此脚本对象的本子方法来实现Java接口。这防止了只好调用脚本全局函数的接口方法。脚本对象足以积攒接口达成景况。

import javax.script.*;

public class RunnableImplObject {
    public static void main(String[] args) throws Exception {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");

        // JavaScript code in a String
        String script = "var obj = new Object(); obj.run = function() { println('run method called'); }";

        // evaluate script
        engine.eval(script);

        // get script object on which we want to implement the interface with
        Object obj = engine.get("obj");

        Invocable inv = (Invocable) engine;

        // get Runnable interface object from engine. This interface methods
        // are implemented by script methods of object 'obj'
        Runnable r = inv.getInterface(obj, Runnable.class);

        // start a new thread that runs the script implemented
        // runnable interface
        Thread th = new Thread(r);
        th.start();
    }
}

本子的多功能域

在 script
variables 例子中,我们见到如何将应用对象暴光为脚本的全局变量。它有希望暴露为四个全局的法力域 。
单作用域是javax.script.Bindings的实例中.
那一个借口派生至java.util.Map<String, Object>。 scope
键值对的成团,在那之中键为非空、非空字符串。 多scopes
是 javax.script.ScriptContext 接口帮忙的。协理四个或两个脚本上下文与连锁的域绑定。默许情状下,
每二个本子引擎都有三个默许的脚本上下文。 默许的剧本上下文有起码一个域叫 ”ENGINE_SCOPE”。差异地的脚本上下文协理可以透过 getscopes 方法赢得。

import javax.script.*;

public class MultiScopes {
    public static void main(String[] args) throws Exception {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");

        engine.put("x", "hello");
        // print global variable "x"
        engine.eval("println(x);");
        // the above line prints "hello"

        // Now, pass a different script context
        ScriptContext newContext = new SimpleScriptContext();
        Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE);

        // add new variable "x" to the new engineScope        
        engineScope.put("x", "world");

        // execute the same script - but this time pass a different script context
        engine.eval("println(x);", newContext);
        // the above line prints "world"
    }
}

JavaScript 脚本引擎

Sun的JDK 6中包涵了三个依照 Mozilla
Rhino JavaScript
脚本引擎。 那么些引擎是基于版本为1.6途观2的Mozilla Rhino 。好多 Rhino
达成都被含有在内。少部分组件由于大小和平安原因被免去了:

  1. JavaScript转字节码编译 (也称 ”优化器”卡塔尔.。此功效信任一个类生成库。 去掉本效率意味着:JavaScript是分解实施,且不影响脚本推行,因为优化器是晶莹剔透的。
  2. Rhino的JavaAdapter
    也被去掉了。 Java艾达pter是八个JavaScript可扩张Java类和JavaScript可达成Java接口功能。此意义也是须求类生成库的。大家把Rhino的JavaAdapter替换为Sun实现的JavaAdapter。在Sun的兑现中,仅仅达成了JavaScript对象可达成Java单接口作用。举个例子,上面包车型客车代码会正确施行。

           var v = new java.lang.Runnable() {
                        run: function() { print('hello'); }
                   }
           v.run();
    

    在大多数气象下,JavaAdapter是使用佚名类语法来兑现单接口。
    使用JavaAdapter来扩大Java类或落成多接口并不普及。

  3. E4X (ECMAScript for XML – ECMA Standard 357卡塔尔国 被去掉了. 使用XML
    JavaScript代码会生出一个语法错误.
    请在乎,E4X帮忙ECMAScript规范是可选的-省略E4X的落到实处是被扶持也是格外ECMAScript 。

  4. Rhino的一声令下行工具 (Rhino shell, debugger 等卡塔尔(قطر‎未有被含有在内。但你能够用利用 jrunscript来代替。

JavaScript与Java的通信

在超越1/4境况下,访谈Java类、对象和艺术很简短。从JavaScript中寻访属性和方式与同Java中相符。这里,大家出色JavaScript
Java访问的主要方面.。更加多的内情请阅读。上边是部分JavaScript访问Java的代码片段。本节需求部分JavaScript知识。如若您准备选择JSENVISION-2第23中学国和欧洲JavaScript脚本语言,那么本节得以跳过。

引入Java 包, 类

停放的函数importPackage 和importClass 能够用来引进Java 包和类。

// Import Java packages and classes 
// like import package.*; in Java
importPackage(java.awt);
// like import java.awt.Frame in Java
importClass(java.awt.Frame);
// Create Java Objects by "new ClassName"
var frame = new java.awt.Frame("hello");
// Call Java public methods from script
frame.setVisible(true);
// Access "JavaBean" properties like "fields"
print(frame.title);

全局变量Packages也足以用于访谈Java包。举例: Packages.java.util.VectorPackages.javax.swing.JFrame.
请小心: ”java” 是
“Packages.java”的长足援引。还也可以有部分也正是的异常快援用前缀 : javax, org,
edu, com, net, 所以差非常少具有的 JDK 平台下的类都足以不选拔”Packages”
前缀而访问到。

请小心,java.lang不是暗中同意引进的 (与Java差别卡塔尔国,因为会与 JavaScript’s
内置的 Object, Boolean, Math 等矛盾。

importPackage 和importClass 函数”污染”
了JavaScript中的全局变量。为了防止这种情状,你能够利用JavaImporter。

// create JavaImporter with specific packages and classes to import

var SwingGui = new JavaImporter(javax.swing,
                            javax.swing.event,
                            javax.swing.border,
                            java.awt.event);
with (SwingGui) {
    // within this 'with' statement, we can access Swing and AWT
    // classes by unqualified (simple) names.

    var mybutton = new JButton("test");
    var myframe = new JFrame("test");
}

C创设和平运动用Java的数组

在JavaScript中,创造三个对象时与Java中一律,而创建Java数组时需求显式的施用Java反射。但假使创造好后,访谈当中的元素或得到大小就和Java中大同小异。 此外,也能够接纳脚本数组用在Java方法中希望的Java数组(因为能够自行转变卡塔尔国。所以在大部分动静下大家无需显式地创立Java数组。

// create Java String array of 5 elements
var a = java.lang.reflect.Array.newInstance(java.lang.String, 5);

// Accessing elements and length access is by usual Java syntax
a[0] = "scripting is great!";
print(a.length);

实现Java 接口

在JavaScript中,能够应用Java佚名类语法方式落到实处Java中接口:

var r  = new java.lang.Runnable() {
    run: function() {
        print("running...n");
    }
};

// "r" can be passed to Java methods that expect java.lang.Runnable
var th = new java.lang.Thread(r);
th.start();

当接口中唯有一个急需贯彻的法亥时,你能够团结传入脚本的函数(因为能够自行调换卡塔尔。

function func() {
     print("I am func!");
}

// pass script function for java.lang.Runnable argument
var th = new java.lang.Thread(func);
th.start();

重载

Java方法是利用参数类型重载的。在Java中,重载发生在编译阶段 (试行 javac卡塔尔。当脚本中调用Java方法时,脚本的翻译器或编写翻译器须要选取合适的法子。对于JavaScript引擎,您不供给做此外极其的——准确的Java方法重载变体是依照参数类型接收的。
但一时,您大概希望(或有卡塔尔国显式地筛选三个特定的过载变体。

var out = java.lang.System.out;

// select a particular println function 
out["println(java.lang.Object)"]("hello");

越来越多JavaScript的Java方法重载细节阅读

自定义脚本引擎

我们不会覆盖的JSWrangler-223协作脚本引擎完毕细节. 起码,
您须求落实javax.script.ScriptEngine 和javax.script.ScriptEngineFactory 接口。 抽象类javax.script.AbstractScriptEngine 提供了一些ScriptEngine 接口中定义的法子。

在最早兑现 JSLacrosse-223
引擎此前,您或者需求下载  http://scripting.dev.java.net 工程。那个工程维护了一部分盛行的开源脚本语言的 JSQX56-223
达成。

引用

  • JSR-223 Scripting for the Java
    Platform
  • JavaScript Developer Connection
  • Java Method Overloading and LiveConnect
    3
  • Rhino:JavaScript for Java
  • Scripting Java (from
    JavaScript)
  • scripting.dev.java.net project

发表评论

电子邮件地址不会被公开。 必填项已用*标注