- 浏览: 64776 次
- 性别:
- 来自: 重庆
文章分类
最新评论
一、脚本语言的支持
JSR 223中规范了在Java虚拟机上运行的脚本语言与Java程序之间的交互方式。JSR 233是JavaSE6的一部分,在Java表中API中的包是javax.script。目前Java虚拟机支持比较多的脚本语言,比较流行的有JavaScript、Scala、JRuby、Jython和Groovy等。
1. 脚本引擎
Java中执行脚本需要脚本语言对应的脚本引擎,JSR 223定义了脚本引擎的注册和查找机制。JavaSE6中自带了JavaScript语言的脚本引擎,基于Mozilla的Rhino实现,可以通过三种方式查找脚本引擎:
① 通过脚本名称获取:
② 通过文件扩展名获取:
③ 通过MIME类型来获取:
如下代码,查找注册JavaScript脚本引擎,打印"Hello!",JavaScript脚本中的println是Rhino引擎额外提供的方法。
2. 语言绑定
脚本语言支持API使用语言绑定对象实现Java语言编写的程序与脚本语言间的数据传递。语言绑定对象实际上就是一个简单的哈希表,用来存放和获取需要共享的数据,其定义的接口为javax.script.Bindings,继承自java.util.Map接口。一个脚本引擎在执行过程中可能会使用多个语言绑定对象,不同语言绑定对象的作用域不同。ScriptEngine类提供out和get方法对脚本引擎中特定作用域的默认语言绑定对象进行操作。
使用默认的语言绑定对象:
亦可以自定义语言绑定对象(如语言绑定对象中包含程序自己独有的数据等情形……):
3. 脚本执行的上下文
脚本引擎通过执行过程中的上下文对象获取与脚本执行相关的信息,同时允许程序员通过此对象配置脚本引擎的行为。其上下文对象来自javax.script.ScriptContext接口,类似于J2EE中javax.servlet.ServletContext接口,该接口主要包含3类信息:
① 输入输出
默认情况下,脚本输入输出都是在标准控制台中,可以通过setReader和setWriter方法对输出流进行重定向,可以通过setErrorWriter方法进行错误输出重定向。
② 自定义属性
上下文中通过setAttribute和getAttribute方法获取和设置属性,类似于ServletContext中设置和获取属性操作。与ServletContext中不同的是,ScriptContext中的属性是有作用域之分的,ScriptContext按不同的顺序在不同的作用域中进行属性查找(类似于JSP中EL表达式属性的作用域)。通过ScriptContext的getScopes可以得到其中所有可用的作用域,其中预定义了两个作用域:常量ScriptContext.ENGINE_SCOPE(当前的脚本引擎)和ScriptContext.GLOBAL_SCOPE(从同一引擎工厂中创建的所有脚本引擎对象)。
③ 语言绑定对象
语言绑定对象位于ScriptContext中,同样也有作用域之分,范围越小,优先级越高。执行如下代码,输出的name值为Bob。
也可以通过ScriptContext获取语言绑定对象:
前面说到语言绑定对象存在于上下文环境中,故context中保存的自定义属性其实也是保存于语言绑定对象中的,如2中的语言绑定。
4. 脚本编译
脚本语言一般均是解释执行的,相对于编译执行的语言,效率较低一些。当脚本语言需要多次重复执行时,可以先对煎熬本进行编译,避免重复解析,提高效率(注:脚本编译需要脚本引擎支持,实现javax.script.Compilable接口)。JavaSE中自带的JavaScript引擎是支持对脚本进行编译的,编译的脚本用javax.script.CompiledScript来表示。
5. 方法调用
Java虚拟机支持脚本的意义在于实现函数式的编程,即脚本中最重要的便是方法。一些脚本引擎允许使用者单独调用脚本中的某个方法,支持此操作的脚本引擎可以通过实现javax.script.Invocable接口,支持顶层方法或者某对象中成员方法的调用。使用方法调用时最好先检查脚本引擎是否实现了Invocable接口,JavaSE中的JavaScript引擎已实现了Invocable接口。
① 在Java中调用脚本中的顶层方法
② 调用脚本中某对象的成员方法
③ 指定脚本中的方法为Java接口的实现
Greet是Java实现的接口,包含一个方法getGreeting,通过Invocable.getInterface()方法指定脚本中的方法为Java接口的实现。
JSR 223中规范了在Java虚拟机上运行的脚本语言与Java程序之间的交互方式。JSR 233是JavaSE6的一部分,在Java表中API中的包是javax.script。目前Java虚拟机支持比较多的脚本语言,比较流行的有JavaScript、Scala、JRuby、Jython和Groovy等。
1. 脚本引擎
Java中执行脚本需要脚本语言对应的脚本引擎,JSR 223定义了脚本引擎的注册和查找机制。JavaSE6中自带了JavaScript语言的脚本引擎,基于Mozilla的Rhino实现,可以通过三种方式查找脚本引擎:
① 通过脚本名称获取:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
② 通过文件扩展名获取:
ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("js");
③ 通过MIME类型来获取:
ScriptEngine engine = new ScriptEngineManager().getEngineByMimeType("text/javascript");
如下代码,查找注册JavaScript脚本引擎,打印"Hello!",JavaScript脚本中的println是Rhino引擎额外提供的方法。
public class BasicScripting { public void greet() throws ScriptException { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("JavaScript"); //ScriptEngine engine = manager.getEngineByExtension("js"); //ScriptEngine engine = manager.getEngineByMimeType("text/javascript"); if (engine == null) { throw new RuntimeException("找不到JavaScript语言执行引擎。"); } engine.eval("println('Hello!');"); } public static void main(String[] args) { try { new BasicScripting().greet(); } catch (ScriptException ex) { Logger.getLogger(BasicScripting.class.getName()).log(Level.SEVERE, null, ex); } } }
2. 语言绑定
脚本语言支持API使用语言绑定对象实现Java语言编写的程序与脚本语言间的数据传递。语言绑定对象实际上就是一个简单的哈希表,用来存放和获取需要共享的数据,其定义的接口为javax.script.Bindings,继承自java.util.Map接口。一个脚本引擎在执行过程中可能会使用多个语言绑定对象,不同语言绑定对象的作用域不同。ScriptEngine类提供out和get方法对脚本引擎中特定作用域的默认语言绑定对象进行操作。
使用默认的语言绑定对象:
public void useDefaultBinding() throws ScriptException { ScriptEngine engine = getJavaScriptEngine(); engine.put("name", "Alex"); engine.eval("var message = 'Hello, ' + name;"); engine.eval("println(message);"); Object obj = engine.get("message"); System.out.println(obj); }
亦可以自定义语言绑定对象(如语言绑定对象中包含程序自己独有的数据等情形……):
public void useCustomBinding() throws ScriptException { ScriptEngine engine = getJavaScriptEngine(); Bindings bindings = new SimpleBindings(); bindings.put("hobby", "playing games"); engine.eval("println('I like ' + hobby);", bindings); }
3. 脚本执行的上下文
脚本引擎通过执行过程中的上下文对象获取与脚本执行相关的信息,同时允许程序员通过此对象配置脚本引擎的行为。其上下文对象来自javax.script.ScriptContext接口,类似于J2EE中javax.servlet.ServletContext接口,该接口主要包含3类信息:
① 输入输出
默认情况下,脚本输入输出都是在标准控制台中,可以通过setReader和setWriter方法对输出流进行重定向,可以通过setErrorWriter方法进行错误输出重定向。
//例:将输出重定向到文件 public void scriptToFile() throws IOException, ScriptException { ScriptEngine engine = getJavaScriptEngine(); ScriptContext context = engine.getContext(); context.setWriter(new FileWriter("output.txt")); engine.eval("println('Hello World!');"); }
② 自定义属性
上下文中通过setAttribute和getAttribute方法获取和设置属性,类似于ServletContext中设置和获取属性操作。与ServletContext中不同的是,ScriptContext中的属性是有作用域之分的,ScriptContext按不同的顺序在不同的作用域中进行属性查找(类似于JSP中EL表达式属性的作用域)。通过ScriptContext的getScopes可以得到其中所有可用的作用域,其中预定义了两个作用域:常量ScriptContext.ENGINE_SCOPE(当前的脚本引擎)和ScriptContext.GLOBAL_SCOPE(从同一引擎工厂中创建的所有脚本引擎对象)。
public void scriptContextAttribute() { ScriptEngine engine = getJavaScriptEngine(); ScriptContext context = engine.getContext(); context.setAttribute("name", "Alex", ScriptContext.GLOBAL_SCOPE); context.setAttribute("name", "Bob", ScriptContext.ENGINE_SCOPE); context.getAttribute("name"); //值为Bob }
③ 语言绑定对象
语言绑定对象位于ScriptContext中,同样也有作用域之分,范围越小,优先级越高。执行如下代码,输出的name值为Bob。
public void scriptContextBindings() throws ScriptException { ScriptEngine engine = getJavaScriptEngine(); ScriptContext context = engine.getContext(); Bindings bindings1 = engine.createBindings(); bindings1.put("name", "Alex"); context.setBindings(bindings1, ScriptContext.GLOBAL_SCOPE); Bindings bindings2 = engine.createBindings(); bindings2.put("name", "Bob"); context.setBindings(bindings2, ScriptContext.ENGINE_SCOPE); engine.eval("println(name);"); //Bob }
也可以通过ScriptContext获取语言绑定对象:
public void useScriptContextValues() throws ScriptException { ScriptEngine engine = getJavaScriptEngine(); ScriptContext context = engine.getContext(); Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE); bindings.put("name", "Alex"); engine.eval("println(name);"); }
前面说到语言绑定对象存在于上下文环境中,故context中保存的自定义属性其实也是保存于语言绑定对象中的,如2中的语言绑定。
public void attributeInBindings() throws ScriptException { ScriptEngine engine = getJavaScriptEngine(); ScriptContext context = engine.getContext(); context.setAttribute("name", "Alex", ScriptContext.GLOBAL_SCOPE); engine.eval("println(name);"); }
4. 脚本编译
脚本语言一般均是解释执行的,相对于编译执行的语言,效率较低一些。当脚本语言需要多次重复执行时,可以先对煎熬本进行编译,避免重复解析,提高效率(注:脚本编译需要脚本引擎支持,实现javax.script.Compilable接口)。JavaSE中自带的JavaScript引擎是支持对脚本进行编译的,编译的脚本用javax.script.CompiledScript来表示。
public class ScriptCompile extends JsScriptRunner { //对脚本进行编译 public CompiledScript compile(String scriptText) throws ScriptException { ScriptEngine engine = getJavaScriptEngine(); if (engine instanceof Compilable) { CompiledScript script = ((Compilable) engine).compile(scriptText); return script; } return null; } //先编译再执行 public void run(String scriptText) throws ScriptException { CompiledScript script = compile(scriptText); if (script == null) { return; } for (int i = 0; i < 100; i++) { script.eval(); } } public static void main(String[] args) { ScriptCompile sc = new ScriptCompile(); try { sc.run("println('Hello');"); } catch (ScriptException ex) { Logger.getLogger(ScriptCompile.class.getName()).log(Level.SEVERE, null, ex); } } }
5. 方法调用
Java虚拟机支持脚本的意义在于实现函数式的编程,即脚本中最重要的便是方法。一些脚本引擎允许使用者单独调用脚本中的某个方法,支持此操作的脚本引擎可以通过实现javax.script.Invocable接口,支持顶层方法或者某对象中成员方法的调用。使用方法调用时最好先检查脚本引擎是否实现了Invocable接口,JavaSE中的JavaScript引擎已实现了Invocable接口。
① 在Java中调用脚本中的顶层方法
public void invokeFunction() throws ScriptException, NoSuchMethodException { ScriptEngine engine = getJavaScriptEngine(); String scriptText = "function greet(name) { println('Hello, ' + name); } "; engine.eval(scriptText); Invocable invocable = (Invocable) engine; invocable.invokeFunction("greet", "Alex"); }
② 调用脚本中某对象的成员方法
public void invokeMethod() throws ScriptException, NoSuchMethodException { ScriptEngine engine = getJavaScriptEngine(); String scriptText = "var obj = { getGreeting : function(name) { return 'Hello, ' + name; } }; "; engine.eval(scriptText); Invocable invocable = (Invocable) engine; Object scope = engine.get("obj"); Object result = invocable.invokeMethod(scope, "getGreeting", "Alex"); //第一个参数为方法所属对象 System.out.println(result); }
③ 指定脚本中的方法为Java接口的实现
Greet是Java实现的接口,包含一个方法getGreeting,通过Invocable.getInterface()方法指定脚本中的方法为Java接口的实现。
public void useInterface() throws ScriptException { ScriptEngine engine = getJavaScriptEngine(); String scriptText = "function getGreeting(name) { return 'Hello, ' + name; } "; engine.eval(scriptText); Invocable invocable = (Invocable) engine; Greet greet = invocable.getInterface(Greet.class); System.out.println(greet.getGreeting("Alex")); }
发表评论
-
SpingMVC第一个拦截器未执行BUG分析
2016-07-15 16:24 2414问题描述: SpringMvc项目中使用<mvc: ... -
MySQL JDBC的setFetchSize
2014-12-05 15:09 5349正常情况下MySQL的JDBC是不支持setFetc ... -
Java SE 6 HotSpot虚拟机的垃圾回收机制
2012-10-31 21:25 1266官方资料,关于Java SE 6 HotSpot虚拟机的gar ... -
Java语言的动态性支持(三)
2012-10-30 23:23 0三、Java7中的方法句柄 方法句柄(Metho ... -
Java语言的动态性支持(二)
2012-10-27 23:08 4791二、Java反射API Jav ... -
Java并发程序设计-注解
2012-10-24 10:50 90351. 类Annotation 3个Annotation描述类的 ... -
Java7语法新特性
2012-10-24 00:39 15328Java7语法新特性: 1. switch中增加对Strin ... -
Java Applet小结
2011-12-03 23:44 73371. Applet基础 在网页 ...
相关推荐
NULL 博文链接:https://uuhorse.iteye.com/blog/1706466
这种探索对于Java开发者来说是一个重要的启示,它提示我们可以在保持Java语言特性的同时,通过合理的机制引入动态性,以适应快速变化的软件开发需求。 文章最后指出,随着计算机时代的发展,编程语言和开发技术也在...
#### 七、动态性 Java支持动态加载类和库,这意味着应用程序可以根据需要动态地扩展其功能。这种特性使得Java程序能够在运行时适应变化的环境,同时也为开发者提供了更大的灵活性。Java的平台独立性也使得它可以在...
* 体系结构中立(Architecture neutral):Java语言环境提供了一个用于访问底层操作系统功能的可扩展类库,使得Java应用程序能在支持Java的各种平台上运行。 * 可移植性(Portable):Java语言的最大特点是“一次...
Java语言起源于SUN公司的Oak项目,最初旨在为消费性电子产品提供一个小型分布式系统软件,以适应异构网络和多主机架构,确保信息安全传递。然而,Oak在消费市场并未取得预期的成功。随着互联网的兴起和HTML(超文本...
Java动态性是Java编程语言中的一个重要特性,它使得程序在运行时可以改变其结构,比如添加、删除或修改类和对象的行为。这一特性使得Java在处理复杂和灵活的问题时具有强大的能力,尤其在开发框架、插件系统以及元...
Java语言概述 Java是一种广泛使用的高级编程语言,由Sun Microsystems的James Gosling、Bill Joy和Eric Schmidt等人在1991年发起的“Green Project”中孕育而生。最初,这个项目的目标是为消费电子产品市场,特别是...
#### 一、JAVA语言的起源与特性 **1.1 Java的历史背景** - **1.1.1 Java的起源** - Java最初由Sun Microsystems的一位名为James Gosling的工程师领导开发,项目代号为“Green”,最初的目的是为了开发家用电器...
8. **动态语言支持**:JRuby、Groovy等基于Java平台的动态语言,可以通过JVM与Java代码交互,提供更强的动态性。 9. **Bytecode操作库**:如ASM、BCEL和Javassist等,可以用于动态生成和修改字节码,实现运行时代码...
- **起始目的**:Java语言最初由Sun Microsystems开发,旨在为消费性电子产品如PDA、电子游戏机等创建一个小巧且安全的分布式系统软件。最初计划使用C++语言,但由于其复杂性和安全性不足,转而开发了一种新的语言...
Groovy是一种基于Java平台的动态脚本语言,它在Java开发者中越来越受欢迎,因为它提供了简洁、灵活的语法,以及强大的动态编程能力。Groovy与Java兼容性极佳,可以直接调用Java类库,使得它在Java生态系统中具有广泛...
- **动态**:Java支持运行时加载类和动态链接等功能,增强了程序的灵活性。 #### Java开发环境配置 描述中提到的“开发环境配置”是指为了进行Java开发所需的一系列准备工作。 - **安装JDK**:JDK (Java ...
#### 一、Java语言起源与发展背景 Java语言最初由Sun Microsystems公司的James Gosling等人在1990年代初期开发,初衷是为了满足消费性电子产品(如PDA、电子游戏机)对小型分布式系统软件的需求。然而,Oak(Java的...
它基于ScriptEngine接口,这是Java Scripting API的一部分,用于支持脚本语言的执行。以下是如何使用GroovyScriptEngine的示例: ```java import javax.script.ScriptEngineManager; import javax.script....
- **动态性**:支持动态加载类,适应变化的需求。 - **丰富的类库**:Java标准库提供了大量预先编写好的类,方便开发。 - **嵌入浏览器运行**:Applet可以直接在浏览器中运行。 3. **Java的用途** - **Web ...
8. **动态性**:Java的动态加载机制允许在运行时动态加载类库,增强了程序的灵活性和扩展性。 #### 三、Java开发环境 Java开发环境主要分为两部分:Java运行环境(JRE)和Java开发工具包(JDK)。 - **JRE**:...