Some useful features of scripting languages are:
Convenience: Most scripting languages are dynamically typed. You can usually create new variables without declaring the variable type, and you can reuse variables to store objects of different types. Additionally, scripting languages tend to automatically perform many types of conversions, such as converting the number 10 to "10" when necessary.
Develop rapid prototypes: You can avoid the edit compile run cycle and just use "edit run"!
Application extension/customization: You can "reify" parts of the application, such as some configuration scripts, business logic/rules and mathematical expressions in financial applications.
Add command line mode to the application for debugging, runtime configuration/deployment time. Most applications these days have a web-based GUI configuration tool. But system administrators/deployers often prefer command line tools. A "standard" scripting language can be used to achieve this purpose, rather than inventing ad hoc scripting languages.
Java Script API is a framework-independent scripting language that uses a scripting engine from Java code. Through the Java Scripting API, it is possible to write custom/extensible applications using the Java language and leave the custom scripting language choice to the end user. Java application developers do not need to choose an extension language during development. If you write your application using the JSR-223 API, your users can use any JSR-223 compliant scripting language.
Java script functionality is in the javax.script package. This is a relatively small, simple API. The starting point for scripts is the ScriptEngineManager class. A ScriptEngineManager object can discover script engines through the jar file's service discovery mechanism. It can also instantiate script engines to interpret scripts written in a specific scripting language. The simplest way to use the scripting interface is as follows:
Create a ScriptEngineManager
object
From the ScriptEngineManager
Get the ScriptEngine
object
Use the eval method of ScriptEngine to execute the script
Now , it’s time to look at some sample code. Some knowledge of JavaScript is helpful to read these examples, but is not required.
From the ScriptEngineManager instance, we get a JavaScript engine instance through the getEngineByName
method. Execute the given JavaScript code through the eval method of the script engine. For simplicity, we do not handle exceptions in this and subsequent examples. The javax.script API has checks and runtime exceptions, and you must handle exceptions appropriately.
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')"); } }
In this example, we call the eval method to receive java.io.Reader as the input source. The read script is executed. This method can execute the script as a file and read the URL and resources using the relevant input stream object.
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])); } }
Suppose we have a file called "test.js" with the following content:
println("This is hello from test.js");
We can use the following method to run the script just now
java EvalFile test.js
When your Java application embeds a script engine and scripts, you may want to expose your application objects as global variables to the script. This example demonstrates how to expose your application objects as global variables to scripts. We create a java.io.File object as a global variable in the application, with the name file. The script can access the variable, for example, it can call its public methods. Note that the syntax for accessing Java objects, fields, and methods depends on the scripting language. JavaScript supports the most "natural" Java-like 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())"); } }
Sometimes, you may need to call a specific script function multiple times. For example, your application menu function may be implemented by a script. . In the operationEvent handling program in the menu, you may need to call a specific script function. The following example demonstrates calling a specific script 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!!" ); } }
If your scripting language is object-based (such as JavaScript) or Object-oriented, you can call script methods on the script object.
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 !!" ); } }
Sometimes it is convenient to implement Java interfaces through script functions or methods instead of calling them in Java. At the same time, through interfaces we can avoid using javax.script API interfaces in many places. We can get an interface implementer object and pass it to different Java APIs. The following example demonstrates implementing the java.lang.Runnable interface via 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.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" } }
Sun的JDK 6中包含了一个基于 Mozilla Rhino JavaScript 脚本引擎。 这个引擎是基于版本为1.6R2的Mozilla Rhino 。多数 Rhino 实现都被包含在内。少部分组件由于大小和安全原因被排除了:
JavaScript转字节码编译 (也称 ”优化器”).。此功能依赖一个类生成库。 去掉本功能意味着:JavaScript是解释执行,且不影响脚本执行,因为优化器是透明的。
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类或实现多接口并不常见。
E4X (ECMAScript for XML – ECMA Standard 357) 被去掉了. 使用XML JavaScript代码会产生一个语法错误. 请注意,E4X支持ECMAScript标准是可选的-省略E4X的实现是被支持也是兼容 ECMAScript 。
Rhino的命令行工具 (Rhino shell, debugger 等) 没有被包含在内。但你可以用使用 jrunscript来代替。
在大多数情况下,访问Java类、对象和方法很简单。从JavaScript中访问属性和方法与同Java中一样。这里,我们突出JavaScript Java访问的重要方面.。下面是一些JavaScript访问Java的代码片段。本节需要一些JavaScript知识。如果你打算使用JSR-223中非JavaScript脚本语言,那么本节可以跳过。
内置的函数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.Vector
, Packages.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"); }
在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);
在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 实现。
The above is the detailed content of Sharing code examples of Java scripted programming guide. For more information, please follow other related articles on the PHP Chinese website!