Java 脚本化编程指南

Java脚本化API为谁准备?

脚本语言的一些有用的特性是:

  • 方便:大多数脚本语言都是动态类型的。您通常可以创建新的变量,而不声明变量类型,并且您可以重用变量来存储不同类型的对象。此外,脚本语言往往会自动执行许多类型的转换,例如, 必要时 将数字10转换为“10”。
  • 开发快速原型:您可以避免编辑编译运行周期,只使用“编辑运行”!
  • 应用扩展/定制:你可以“具体化”的部分应用程序,例如一些配置脚本,业务逻辑/规则和财务应用中的数学表达式 。
  • 为应用添加命令行模式,用于调试、运行时配置/部署时间。现在大多数应用程序都有一个基于Web的GUI配置工具。但是系统管理员/部署人员常常喜欢命令行工具。一个“标准”的脚本语言可以用来实现这个目的,而不是发明特设的脚本语言。

Java 脚本 API 是一种独立于框架的脚本语言,使用来自于Java代码的脚本引擎 。通过java脚本API,可以使用Java语言编写定制/可扩展的应用程序并将自定义脚本语言选择留给最终用户 。Java 应用程序开发者不需要在开发过程中选择扩展语言。如果你使用JSR-223 API来编写应用,那么你的用户可以使用任何JSR-223兼容的脚本语言。

脚本包

Java 脚本功能是在 javax.script 包中。这是一个比较小的,简单的API。脚本的出发点是 ScriptEngineManager 类。一个 ScriptEngineManager 对象可以通过jar文件的服务发现机制发现脚本引擎。它也可以实例化脚本引擎来解释使用特定的脚本语言编写的脚本。使用脚本编程接口的最简单的方法如下:

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

现在,是时候看一些样本代码了。了解一些JavaScript有助于阅读这些例子,但不是强制的。

实例

“Hello,World”

从ScriptEngineManager实例中,我们通过 getEngineByName 方法得到一个JavaScript引擎实例。通过脚本引擎的eval方法来执行给定的JavaScript代码。为简便起见,本例以及随后的例子中,我们不对异常进行处理。javax.script API有检查和运行时异常,你必须妥善处理异常。

执行一个脚本文件

在这个例子中,我们调用eval方法来接收java.io.Reader作为输入源。读入的脚本被执行。这种方式能够成文件执行脚本,用相关的输入流对象读取URL和资源。

假设我们有一个叫”test.js”的文件,里面的内容如下:

我们可以使用下面的方式来运行刚刚的脚本

脚本变量

当你的java应用程序嵌入脚本引擎和脚本,你可能希望将您的应用程序对象为全局变量暴露于脚本中。这个例子演示了如何将您的应用程序对象作为全局变量暴露于脚本中。我们在应用程序中创建一个 java.io.File对象作为全局变量,名称是file。该脚本可以访问变量,例如,它可以调用它的公共方法。注意访问java对象、领域和方法的语法依赖于脚本语言。JavaScript支持最“自然”的类似java的语法。

调用脚本函数和方法

有些时候,你可能需要多次调用一个特定脚本函数,例如你的应用程序菜单功能可能由脚本来实现。在菜单中的操作事件处理程序中,可能需要调用一个特定的脚本函数。下面的示例演示在Java代码调用一个特定的脚本。

如果你的脚本语言是基于对象(如JavaScript)或面向对象的,你可以在脚本对象上调用脚本方法。

通过脚本实现Java接口

有些时候通过脚本函数或者方法可以很方便的实现java接口,而不是在Java中调用。同时,通过接口我们可以避免在很多地方使用javax.script API接口。我们可以得到一个接口实现者对象并将其传递给不同的Java api。下面的例子演示了通过脚本实现 java.lang.Runnable接口。

如果你的脚本语言是基于对象或者面向对象的,可以通过脚本对象的脚本方法来实现Java接口。这避免了不得不调用脚本全局函数的接口方法。脚本对象可以存储接口实现状态。

脚本的多作用域

在 script variables 例子中,我们看到怎样将应用对象暴露为脚本的全局变量。它有可能暴露为多个全局的作用域 。 单作用域是javax.script.Bindings的实例中. 这个借口派生至java.util.Map<String, Object>。 scope 键值对的集合,其中键为非空、非空字符串。 多scopes 是 javax.script.ScriptContext 接口支持的。支持一个或多个脚本上下文与相关的域绑定。默认情况下, 每一个脚本引擎都有一个默认的脚本上下文。 默认的脚本上下文有至少一个域叫 ”ENGINE_SCOPE”。不同域的脚本上下文支持可以通过 getscopes 方法获取。

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单接口功能。例如,下面的代码会正确执行。
  1. 在大多数情况下,JavaAdapter是采用匿名类语法来实现单接口。 使用JavaAdapter来扩展Java类或实现多接口并不常见。
  2. E4X (ECMAScript for XML – ECMA Standard 357) 被去掉了. 使用XML JavaScript代码会产生一个语法错误. 请注意,E4X支持ECMAScript标准是可选的-省略E4X的实现是被支持也是兼容 ECMAScript 。
  3. Rhino的命令行工具 (Rhino shell, debugger 等) 没有被包含在内。但你可以用使用 jrunscript来代替。
  4. JavaScript与Java的通信

在大多数情况下,访问Java类、对象和方法很简单。从JavaScript中访问属性和方法与同Java中一样。这里,我们突出JavaScript Java访问的重要方面.。更多的细节请阅读http://www.mozilla.org/rhino/scriptjava.html。下面是一些JavaScript访问Java的代码片段。本节需要一些JavaScript知识。如果你打算使用JSR-223中非JavaScript脚本语言,那么本节可以跳过。

引入Java 包, 类

内置的函数importPackageimportClass 可以用于引入Java 包和类。

全局变量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 等冲突。

importPackageimportClass 函数”污染” 了JavaScript中的全局变量。为了避免这种情况,你可以使用JavaImporter。

C创建和使用Java的数组

在JavaScript中,创建一个对象时与Java中一样,而创建Java数组时需要显式的使用Java反射。但一旦创建好后,访问其中的元素或获取大小就和Java中一样。 另外,也可以使用脚本数组用在Java方法中期望的Java数组(因为可以自动转换)。所以在大多数情况下我们不需要显式地创建Java数组。

实现Java 接口

在JavaScript中,可以使用Java匿名类语法形式实现Java中接口:

当接口中只有一个需要实现的方法时,你可以自己传入脚本的函数(因为可以自动转换)。

重载

Java方法是使用参数类型重载的。在Java中,重载发生在编译阶段 (执行 javac)。当脚本中调用Java方法时,脚本的翻译器或编译器需要选择适当的方法。对于JavaScript引擎,您不需要做任何特别的——正确的Java方法重载变体是根据参数类型选择的。 但有时,您可能希望(或有)显式地选择一个特定的过载变体。

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

http://www.mozilla.org/js/liveconnect/lc3_method_overloading.html

自定义脚本引擎

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

在开始实现 JSR-223 引擎之前,您可能需要下载 http://scripting.dev.java.net 工程。这个工程维护了一些流行的开源脚本语言的 JSR-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

本文分享自微信公众号 - java一日一条(mjx_java)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-11-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏流柯技术学院

JMeter专题系列(五)检查点

检查点:我们对用户名和密码进行了参数化,那么怎样来判断jmeter有没有正确调用t.dat里面的文件呢。当然,我们可以从结果图表中查看。但我还是想在“登录”这个...

14830
来自专栏Linyb极客之路

从Java内存模型角度理解安全初始化

如大家所知,Java代码在编译和运行的过程中会对代码有很多意想不到且不受开发人员控制的操作:

12630
来自专栏Ryan Miao

java基础题目总结

有些基础题目由于工作中用的比较少但却又是不可少的,这样回答起来就会反应慢,不确定,不准确,特此开了文章记录遇到的不确定或者回答比较拗口的问题。 1.servle...

36690
来自专栏Android相关

Android---SharedPreferences解析

SharedPreferences真正实现的类是:SharedPreferencesImpl

23130
来自专栏yukong的小专栏

【java并发编程实战1】何为线程安全性线程安全性

多线程问题,一直是我们老生常谈的一个问题,在面试中也会被经常问到,如何去学习理解多线程,何为线程安全性,那么大家跟我的脚步一起来学习一下。

15130
来自专栏我的博客

CI基础知识笔记

1.知识点 $config[‘url_suffix’] = ”;//url后缀 $config[‘enable_query_strings’] = FALS...

29530
来自专栏orientlu

FreeRTOS 消息队列

上面这几中方式中, 除了消息通知, 其他几种实现都是基于消息队列。消息队列作为主要的通信方式, 支持在任务间, 任务和中断间传递消息内容。 这一章介绍 Fre...

68420
来自专栏偏前端工程师的驿站

(cljs/run-at (JSVM. :browser) "命名空间就这么简单")

前言  一个cljs文件定义一个命名空间,通过命名空间可以有效组织代码,这是构建大型系统必备的基础设施。本篇我们就深入理解cljs中的命名空间吧! 好习惯从"头...

22450
来自专栏idba

浅谈 multiprocessing

一前言 使用python进行并发处理多台机器/多个实例的时候,我们可以使用threading ,但是由于著名的GIL存在,实际上threading 并...

10300
来自专栏CodingToDie

Python学习(七):模块 优雅的封装

第7 章 模块 优雅的封装 Table of Contents Python中的模块 使用模块 定义模块 建议 模块的安装 模块搜索路径 作用域 编程是一种美德...

1.4K40

扫码关注云+社区

领取腾讯云代金券