Heim  >  Artikel  >  Java  >  Teilen von Codebeispielen eines Java-Skript-Programmierhandbuchs

Teilen von Codebeispielen eines Java-Skript-Programmierhandbuchs

黄舟
黄舟Original
2017-03-20 10:24:322039Durchsuche

Java ScriptingAPIFür wen ist es?

Einige nützliche Funktionen von Skriptsprachen sind:

  • Komfort: Die meisten Skriptsprachen werden dynamisch typisiert. Normalerweise können Sie neue Variablen erstellen, ohne den Variablentyp zu deklarieren, und Sie können Variablen wiederverwenden, um Objekte unterschiedlichen Typs zu speichern. Darüber hinaus neigen Skriptsprachen dazu, viele Arten von Konvertierungen automatisch durchzuführen, z. B. bei Bedarf die Zahl 10 in „10“ umzuwandeln.

  • Entwickeln Sie schnelle Prototypen: Sie können den Edit-Compile-Run-Zyklus vermeiden und einfach „Edit Run“ verwenden!

  • Anwendungserweiterung/-anpassung: Sie können Teile der Anwendung „reifizieren“, wie etwa einige Konfigurationsskripte, Geschäftslogik/-regeln und mathematische Ausdrücke in Finanzanwendungen.

  • Fügt der Anwendung einen Befehlszeilenmodus für Debugging, Laufzeitkonfiguration/Bereitstellungszeit hinzu. Die meisten Anwendungen verfügen heutzutage über ein webbasiertes GUI-Konfigurationstool. Systemadministratoren/Bereitsteller bevorzugen jedoch häufig Befehlszeilentools. Um diesen Zweck zu erreichen, kann eine „Standard“-Skriptsprache verwendet werden, anstatt Ad-hoc-Skriptsprachen zu erfinden.

Java Script API ist eine Framework-unabhängige Skriptsprache, die eine Skript-Engine aus Java-Code verwendet. Über die Java-Scripting-API ist es möglich, benutzerdefinierte/erweiterbare Anwendungen mit der Java-Sprache zu schreiben und die Wahl der benutzerdefinierten Skriptsprache dem Endbenutzer zu überlassen. Entwickler von Java-Anwendungen müssen während der Entwicklung keine Erweiterungssprache auswählen. Wenn Sie Ihre Anwendung mit der JSR-223-API schreiben, können Ihre Benutzer jede JSR-223-kompatible Skriptsprache verwenden.

Skriptpaket

Java-Skript-Funktionalität ist im Paket javax.script enthalten. Dies ist eine relativ kleine, einfache API. Der Ausgangspunkt für Skripte ist die Klasse ScriptEngineManager. Ein ScriptEngineManager-Objekt kann Skript-Engines über den Diensterkennungsmechanismus der JAR-Datei erkennen. Es kann auch Skript-Engines instanziieren, um in einer bestimmten Skriptsprache geschriebene Skripte zu interpretieren. Der einfachste Weg, die Skriptschnittstelle zu verwenden, ist wie folgt:

  1. Erstellen Sie ein ScriptEngineManager-Objekt

  2. Holen Sie sich das ScriptEngineManager-Objekt von ScriptEngine

  3. Verwendung von ScriptEngine的eval方法执行脚本

Jetzt ist es an der Zeit, sich einen Beispielcode anzusehen. Beim Lesen dieser Beispiele sind Kenntnisse in etwas JavaScript hilfreich, aber nicht zwingend erforderlich.

Instanz

"Hello, World"

Von der ScriptEngineManager-Instanz erhalten wir über die getEngineByName-Methode eine JavaScript-Engine-Instanz. Führen Sie den angegebenen JavaScript-Code über die eval-Methode der Skript-Engine aus. Der Einfachheit halber behandeln wir in diesem und den folgenden Beispielen keine Ausnahmen. Die javax.script-API verfügt über Prüfungen und Laufzeitausnahmen, und Sie müssen Ausnahmen entsprechend behandeln.

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

Führen Sie eine Skriptdatei aus

In diesem Beispiel rufen wir die Methode eval auf, um java.io.Reader als Eingabequelle zu erhalten. Das Leseskript wird ausgeführt. Diese Methode kann das Skript als Datei ausführen und die URL und Ressourcen mithilfe des entsprechenden Eingabestreamobjekts lesen.

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]));
    }
}

Angenommen, wir haben eine Datei namens „test.js“ mit folgendem Inhalt:

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

Wir können die folgende Methode verwenden, um das Skript gerade auszuführen

java EvalFile test.js

Skriptvariablen

Wenn Ihre Java-Anwendung eine Skript-Engine und Skripte einbettet, möchten Sie Ihre Anwendungsobjekte möglicherweise als globale Variablen für das Skript verfügbar machen. Dieses Beispiel zeigt, wie Sie Ihre Anwendungsobjekte als globale Variablen für Skripts verfügbar machen. Wir erstellen ein java.io.File-Objekt als globale Variable in der Anwendung mit dem Namen file. Das Skript kann auf die Variable zugreifen und beispielsweise deren öffentliche Methoden aufrufen. Beachten Sie, dass die Syntax für den Zugriff auf Java-Objekte, -Felder und -Methoden von der Skriptsprache abhängt. JavaScript unterstützt die „natürlichste“ Java-ähnliche Syntax.

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

Aufrufen von SkriptenFunktionenund Methoden

Manchmal müssen Sie eine bestimmte Skriptfunktion möglicherweise mehrmals aufrufen. Beispielsweise kann die Funktion Ihres Anwendungsmenüs aufgerufen werden durch ein Skript zu erreichen. Im Programm Operation Event-Handler im Menü müssen Sie möglicherweise eine bestimmte Skriptfunktion aufrufen. Das folgende Beispiel zeigt den Aufruf eines bestimmten Skripts in Java-Code.

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

Wenn Ihre Skriptsprache objektbasiert (z. B. JavaScript) oder objektorientiert ist, können Sie Skriptmethoden für das Skriptobjekt aufrufen.

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-Schnittstelle über Skript implementieren

Manchmal ist es praktisch, die Java-Schnittstelle über eine Skriptfunktion oder -methode zu implementieren, anstatt sie in Java aufzurufen. Gleichzeitig können wir durch Schnittstellen an vielen Stellen die Verwendung von javax.script-API-Schnittstellen vermeiden. Wir können ein Schnittstellenimplementierungsobjekt abrufen und es an verschiedene Java-APIs übergeben. Das folgende Beispiel demonstriert die Implementierung der java.lang.Runnable-Schnittstelle per Skript.

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.Map994a833a6ffa28d85b72cb15422c29d6。 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.6R2的Mozilla Rhino 。多数 Rhino 实现都被包含在内。少部分组件由于大小和安全原因被排除了:

  1. JavaScript转字节码编译 (也称 ”优化器”).。此功能依赖一个类生成库。 去掉本功能意味着:JavaScript是解释执行,且不影响脚本执行,因为优化器是透明的。

  2. Rhino的JavaAdapter 也被去掉了。 JavaAdapter是一个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的通信

在大多数情况下,访问Java类、对象和方法很简单。从JavaScript中访问属性和方法与同Java中一样。这里,我们突出JavaScript Java访问的重要方面.。下面是一些JavaScript访问Java的代码片段。本节需要一些JavaScript知识。如果你打算使用JSR-223中非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");

自定义脚本引擎

我们不会覆盖的JSR-223兼容脚本引擎实现细节. 至少, 您需要实现javax.script.ScriptEngine 和javax.script.ScriptEngineFactory 接口。 抽象类javax.script.AbstractScriptEngine 提供了一些ScriptEngine 接口中定义的方法。

在开始实现 JSR-223 引擎之前,您可能需要下载。这个工程维护了一些流行的开源脚本语言的 JSR-223 实现。

Das obige ist der detaillierte Inhalt vonTeilen von Codebeispielen eines Java-Skript-Programmierhandbuchs. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn