Java SE6加入了对JSR223的实现,
JSR223旨在定义一个统一的规范,使得java应用程序可以通过一套固定的接口定义与各个脚本引擎交互,从而达到java平台上调用各个脚本语言的目的。接口定义在javax.script下面。从而使是java语言可以执行javascript,ruby,python等动态语言。其中javascript的解析引擎是使用Mozilla Rhino不过是经过修改的。Mozilla Rhino是一个开源的java实现javascript的项目,jdk6中引入了Rhino1.6R2 版本,有了java对javascript的实现,对于java开发人员来说是一个非常便利事情。
下面将介绍如何在java代码中使用javascript。相关的实现在javax.script 包下面。
定义了 Invocable ScriptEngine ScriptEngineFactory Bindings ScriptContext
这5个主要接口。
下面主要介绍这几个接口的使用
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
try {
engine.eval("print ('Hello')");
} catch (ScriptException e) {}
上面一段是非常简单的实现。就是在console 上打出一个Hello。
其中ScriptEngineManager 是驱动管理器,通过sun.misc.service 查找注册的脚本语言。
List<ScriptEngineFactory> list = factory.getEngineFactories();
for(ScriptEngineFactory engineFactory:list){
System.out.println(engineFactory.getEngineName());
}
Mozilla Rhino
通过getEngineFactories() 可以返回当前已经注册的脚本引擎。如果机器上没有安装ruby等启动动态语言,那些将只返回 Mozilla Rhino。
ScriptEngine engine = factory.getEngineByName("javascript");
这段一看就明白获取javascript 的引擎,其实写成factory.getEngineByName("js")
name =[js,rhino,JavaScript,javascript,ECMAScript,ecmascript] 效果是一样的。可以通过上面提到的ScriptEngineFactory 中得到名称列表。
ScriptEngine 接口提供了
public void setContext(ScriptContext context);
public void setBindings(Bindings bindings, int scope);
public Bindings getBindings(int scope);
public Bindings createBindings();
public ScriptContext getContext();
public Object get(String key);
public void put(String key, Object value);
public Object eval(...)
其中 ScriptContext,和 Bindings 只是作为一个属性集合,并不存在其它的含义,只是一种传值的工具。
ScriptEngineManager factory = new ScriptEngineManager();
中提供的一个factory.put(key, value);
这个put 进去的所有值将作为ScriptContext.GLOBAL_SCOPE。
context.getAttribute(key, ScriptContext.ENGINE_SCOPE) 将获取不到value。
如果是context.getAttribute(key, ScriptContext.GLOBAL_SCOPE) 将可以获取的。
每一个新构建出来的ScriptEngine 都会有自己独立的ScriptContext ,同时这个ScriptContext将继承ScriptEngineManager里植入的key-value值。如果在Engine 中修改Context 里面的值 需要使用ScriptContext.ENGINE_SCOPE ,如果使用ScriptContext.GLOBAL_SCOPE 将会把全局变量修改掉:
如下例子:
ScriptEngineManager factory = new ScriptEngineManager();
factory.put("msg", "my=GLOBAL_SCOPE");
{
ScriptEngine engine1 = factory.getEngineByName("javascript");
ScriptContext context1 = engine1.getContext();
context1.setAttribute("msg", "my=ENGINE_SCOPE", ScriptContext.ENGINE_SCOPE);
try {
engine1.eval("println (msg)");
} catch (ScriptException e) {
}
}
{
ScriptEngine engine2 = factory.getEngineByName("javascript");
try {
engine2.eval("println (msg)");
} catch (ScriptException e) {
}
}
console 中出现的是:
my=ENGINE_SCOPE
my=GLOBAL_SCOPE
如果将context1.setAttribute("msg", "my=ENGINE_SCOPE", ScriptContext.GLOBAL_SCOPE); 改成这样
console 中出现的是:
my=ENGINE_SCOPE
my=ENGINE_SCOPE
接口Invocable
这个接口非常有用,可以是java接口类与动态语言的方法合并,实现像调用java 方法一样调用动态语言的方法。
首先 声明一个简单的java接口
public interface JavaInterface {
public void printlnMessage(String msg);
}
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
String script = "function printlnMessage(msg){println(msg);}";
engine.eval(script);
Invocable inv = (Invocable)engine;
JavaInterface i = inv.getInterface(JavaInterface.class);
i.printlnMessage("my-JavaInterface");
如上就可以直接通过调用JavaInterface 就可以实现printlnMessage
同时还有一个非常重要的特性是,动态语言中可以直接实现java对象
public class JavaContext {
private List<String> list = new ArrayList<String>();
public void put(String msg){
list.add(msg);
}
public List<String> get(){
return list;
}
}
这个是一个简单的java类
同样在上面一段代码做一些简单的修改:
public interface JavaInterface {
public void printlnMessage(String msg);
public JavaContext getJavaContext();
}
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
engine.put("javaContext", new JavaContext());
String script = "function printlnMessage(msg){javaContext.put(msg);} function getJavaContext(){return javaContext}";
engine.eval(script);
Invocable inv = (Invocable)engine;
JavaInterface i = inv.getInterface(JavaInterface.class);
i.printlnMessage("my-JavaInterface1");
i.printlnMessage("my-JavaInterface2");
for(String s:i.getJavaContext().get()){
System.out.println(s);
}
最后在console中输出:
my-JavaInterface1
my-JavaInterface2
JSR223旨在定义一个统一的规范,使得java应用程序可以通过一套固定的接口定义与各个脚本引擎交互,从而达到java平台上调用各个脚本语言的目的。接口定义在javax.script下面。从而使是java语言可以执行javascript,ruby,python等动态语言。其中javascript的解析引擎是使用Mozilla Rhino不过是经过修改的。Mozilla Rhino是一个开源的java实现javascript的项目,jdk6中引入了Rhino1.6R2 版本,有了java对javascript的实现,对于java开发人员来说是一个非常便利事情。
下面将介绍如何在java代码中使用javascript。相关的实现在javax.script 包下面。
定义了 Invocable ScriptEngine ScriptEngineFactory Bindings ScriptContext
这5个主要接口。
下面主要介绍这几个接口的使用
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
try {
engine.eval("print ('Hello')");
} catch (ScriptException e) {}
上面一段是非常简单的实现。就是在console 上打出一个Hello。
其中ScriptEngineManager 是驱动管理器,通过sun.misc.service 查找注册的脚本语言。
List<ScriptEngineFactory> list = factory.getEngineFactories();
for(ScriptEngineFactory engineFactory:list){
System.out.println(engineFactory.getEngineName());
}
Mozilla Rhino
通过getEngineFactories() 可以返回当前已经注册的脚本引擎。如果机器上没有安装ruby等启动动态语言,那些将只返回 Mozilla Rhino。
ScriptEngine engine = factory.getEngineByName("javascript");
这段一看就明白获取javascript 的引擎,其实写成factory.getEngineByName("js")
name =[js,rhino,JavaScript,javascript,ECMAScript,ecmascript] 效果是一样的。可以通过上面提到的ScriptEngineFactory 中得到名称列表。
ScriptEngine 接口提供了
public void setContext(ScriptContext context);
public void setBindings(Bindings bindings, int scope);
public Bindings getBindings(int scope);
public Bindings createBindings();
public ScriptContext getContext();
public Object get(String key);
public void put(String key, Object value);
public Object eval(...)
其中 ScriptContext,和 Bindings 只是作为一个属性集合,并不存在其它的含义,只是一种传值的工具。
ScriptEngineManager factory = new ScriptEngineManager();
中提供的一个factory.put(key, value);
这个put 进去的所有值将作为ScriptContext.GLOBAL_SCOPE。
context.getAttribute(key, ScriptContext.ENGINE_SCOPE) 将获取不到value。
如果是context.getAttribute(key, ScriptContext.GLOBAL_SCOPE) 将可以获取的。
每一个新构建出来的ScriptEngine 都会有自己独立的ScriptContext ,同时这个ScriptContext将继承ScriptEngineManager里植入的key-value值。如果在Engine 中修改Context 里面的值 需要使用ScriptContext.ENGINE_SCOPE ,如果使用ScriptContext.GLOBAL_SCOPE 将会把全局变量修改掉:
如下例子:
ScriptEngineManager factory = new ScriptEngineManager();
factory.put("msg", "my=GLOBAL_SCOPE");
{
ScriptEngine engine1 = factory.getEngineByName("javascript");
ScriptContext context1 = engine1.getContext();
context1.setAttribute("msg", "my=ENGINE_SCOPE", ScriptContext.ENGINE_SCOPE);
try {
engine1.eval("println (msg)");
} catch (ScriptException e) {
}
}
{
ScriptEngine engine2 = factory.getEngineByName("javascript");
try {
engine2.eval("println (msg)");
} catch (ScriptException e) {
}
}
console 中出现的是:
my=ENGINE_SCOPE
my=GLOBAL_SCOPE
如果将context1.setAttribute("msg", "my=ENGINE_SCOPE", ScriptContext.GLOBAL_SCOPE); 改成这样
console 中出现的是:
my=ENGINE_SCOPE
my=ENGINE_SCOPE
接口Invocable
这个接口非常有用,可以是java接口类与动态语言的方法合并,实现像调用java 方法一样调用动态语言的方法。
首先 声明一个简单的java接口
public interface JavaInterface {
public void printlnMessage(String msg);
}
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
String script = "function printlnMessage(msg){println(msg);}";
engine.eval(script);
Invocable inv = (Invocable)engine;
JavaInterface i = inv.getInterface(JavaInterface.class);
i.printlnMessage("my-JavaInterface");
如上就可以直接通过调用JavaInterface 就可以实现printlnMessage
同时还有一个非常重要的特性是,动态语言中可以直接实现java对象
public class JavaContext {
private List<String> list = new ArrayList<String>();
public void put(String msg){
list.add(msg);
}
public List<String> get(){
return list;
}
}
这个是一个简单的java类
同样在上面一段代码做一些简单的修改:
public interface JavaInterface {
public void printlnMessage(String msg);
public JavaContext getJavaContext();
}
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
engine.put("javaContext", new JavaContext());
String script = "function printlnMessage(msg){javaContext.put(msg);} function getJavaContext(){return javaContext}";
engine.eval(script);
Invocable inv = (Invocable)engine;
JavaInterface i = inv.getInterface(JavaInterface.class);
i.printlnMessage("my-JavaInterface1");
i.printlnMessage("my-JavaInterface2");
for(String s:i.getJavaContext().get()){
System.out.println(s);
}
最后在console中输出:
my-JavaInterface1
my-JavaInterface2