Maison  >  Article  >  Java  >  Partage d'exemples de code du guide de programmation scripté Java

Partage d'exemples de code du guide de programmation scripté Java

黄舟
黄舟original
2017-03-20 10:24:322013parcourir

Java ScriptingAPIÀ qui s'adresse-t-il ?

Certaines fonctionnalités utiles des langages de script sont :

  • Commodité : la plupart des langages de script sont typés dynamiquement. Vous pouvez généralement créer de nouvelles variables sans déclarer le type de variable et vous pouvez réutiliser des variables pour stocker des objets de différents types. De plus, les langages de script ont tendance à effectuer automatiquement de nombreux types de conversions, comme la conversion du nombre 10 en « 10 » lorsque cela est nécessaire.

  • Développez des prototypes rapides : vous pouvez éviter le cycle d'exécution de la compilation d'édition et utiliser simplement "l'exécution d'édition" !

  • Extension/personnalisation de l'application : vous pouvez « réifier » des parties de l'application, telles que certains scripts de configuration, la logique/règles métier et les expressions mathématiques dans les applications financières.

  • Ajoutez le mode ligne de commande à l'application pour le débogage, la configuration d'exécution/le temps de déploiement. De nos jours, la plupart des applications disposent d'un outil de configuration GUI basé sur le Web. Mais les administrateurs système/déployeurs préfèrent souvent les outils en ligne de commande. Un langage de script « standard » peut être utilisé pour atteindre cet objectif, plutôt que d'inventer des langages de script ad hoc.

L'API Java Script est un langage de script indépendant du framework qui utilise un moteur de script à partir du code Java. Grâce à l'API Java Scripting, il est possible d'écrire des applications personnalisées/extensibles à l'aide du langage Java et de laisser le choix du langage de script personnalisé à l'utilisateur final. Les développeurs d'applications Java n'ont pas besoin de choisir un langage d'extension lors du développement. Si vous écrivez votre application à l'aide de l'API JSR-223, vos utilisateurs peuvent utiliser n'importe quel langage de script compatible JSR-223.

Package de script

La fonctionnalité de script Java se trouve dans le package javax.script. Il s'agit d'une API simple et relativement petite. Le point de départ des scripts est la classe ScriptEngineManager. Un objet ScriptEngineManager peut découvrir les moteurs de script via le mécanisme de découverte de services du fichier jar. Il peut également instancier des moteurs de script pour interpréter des scripts écrits dans un langage de script spécifique. La façon la plus simple d'utiliser l'interface de script est la suivante :

  1. Créez un objet ScriptEngineManager

  2. Obtenez l'objet ScriptEngineManager à partir de ScriptEngine

  3. Utilisation de ScriptEngine的eval方法执行脚本

Maintenant, il est temps d'examiner un exemple de code. Connaître un peu de JavaScript est utile mais pas obligatoire lors de la lecture de ces exemples.

Instance

"Hello, World"

À partir de l'instance ScriptEngineManager, nous obtenons une instance de moteur JavaScript via la méthode getEngineByName. Exécutez le code JavaScript donné via la méthode eval du moteur de script. Par souci de simplicité, nous ne gérons pas les exceptions dans cet exemple et les suivants. L'API javax.script comporte des vérifications et des exceptions d'exécution, et vous devez gérer les exceptions de manière appropriée.

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

Exécuter un fichier script

Dans cet exemple, nous appelons la méthode eval pour recevoir java.io.Reader comme source d'entrée. Le script de lecture est exécuté. Cette méthode peut exécuter le script sous forme de fichier et lire l'URL et les ressources à l'aide de l'objet de flux d'entrée approprié.

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

Supposons que nous ayons un fichier appelé "test.js" avec le contenu suivant :

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

Nous pouvons utiliser la méthode suivante pour exécuter le script tout de suite

java EvalFile test.js

Variables de script

Lorsque votre application Java intègre un moteur de script et des scripts, vous souhaiterez peut-être exposer vos objets d'application en tant que variables globales au script. Cet exemple montre comment exposer vos objets d'application en tant que variables globales aux scripts. Nous créons un objet java.io.File en tant que variable globale dans l'application, avec le nom file. Le script peut accéder à la variable, par exemple, il peut appeler ses méthodes publiques. Notez que la syntaxe d'accès aux objets, champs et méthodes Java dépend du langage de script. JavaScript prend en charge la syntaxe la plus « naturelle » de type 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())");
    }
}

Appel de scriptsFonctionset méthodes

Parfois, vous devrez peut-être appeler une fonction de script spécifique plusieurs fois. Par exemple, la fonction de votre menu d'application peut être appelée. par un scénario à réaliser. Dans le programme opération gestionnaire d'événements dans le menu, vous devrez peut-être appeler une fonction de script spécifique. L'exemple suivant montre l'appel d'un script spécifique dans du code 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!!" );
    }
}

Si votre langage de script est basé sur des objets (comme JavaScript) ou orienté objet, vous pouvez appeler des méthodes de script sur l'objet de script.

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

Implémentation d'interfaces Java via des scripts

Parfois, il est facile d'implémenter des interfaces Java via des fonctions ou des méthodes de script au lieu de les appeler en Java. Dans le même temps, grâce aux interfaces, nous pouvons éviter d'utiliser les interfaces API javax.script dans de nombreux endroits. Nous pouvons obtenir un objet d’implémentation d’interface et le transmettre à différentes API Java. L'exemple suivant montre l'implémentation de l'interface java.lang.Runnable via un script.

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 实现。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn