脚本、编译和注解处理
Java平台的脚本
添加脚本引擎
Java SE默认支持对JavaScript的解释。
ScriptEngineManager manager = new ScriptEngineManager();
//获取所有发现的引擎工长列表
List<ScriptEngineFactory> factoryList = manager.getEngineFactories();
for(ScriptEngineFactory factory : factoryList){
//获取引擎工厂名称
logger.info("engine name: "+factory.getEngineName());
//该引擎工厂所了解的名字
logger.info("getNames: " + factory.getNames());
//该引擎工厂所了解的文件扩展名
logger.info("getExtensions: " + factory.getExtensions());
//该引擎工厂所了解的MIME类型
logger.info("getMimeTypes: " + factory.getMimeTypes());
}
默认情况下,输出结果如下:
Java SE 8之前默认使用的是Rnino js脚本引擎,从Java SE 8 开始,默认使用Nashorn作为js脚本引擎。
如果需要对其它脚本进行支持,需要添加相应的JAR包。如增加对Groovy脚本的支持:
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>3.0.3</version>
<type>pom</type>
</dependency>
只需要加入Groovy的jar包,项目就可以支持Groovy了。
获取脚本引擎对象
通过上面对引擎的探测,我们知道了当前应用支持的脚本。我们就可以根据使用ScriptEngineMaanager
来获得引擎对象:
//指定名称获取
ScriptEngine jsEngine = manager.getEngineByName("JavaScript");
//指定扩展名获取
ScriptEngine jsEngine = manager.getEngineByExtension("js");
//指定MIME类型获取
ScriptEngine jsEngine = manager.getEngineByMimeType("application/javascript");
脚本赋值与绑定
一旦获得了引擎,我们就可以调用脚本了。
//直接执行脚本字符串
Object result = jsEngine.eval(jsString);
//若脚本在一个文件中,需要先打开一个Reader,然后再调用
Object result = jsEngine.eval(reader);
变量绑定
//引擎作用域
jsEngine.put(k,value);//为脚本中的某个变量赋值
jsEngine.get(k);//获取脚本中某个变量的值
// 全局作用域
manager.put(k,value);
除了想引擎或全局作用域绑定变量到外,还可以将所有变量绑定集中在类型为Bindings
的对象中,然后将其传递给eval
方法:
Bindings scops = engine.createBindings();
scops.put(k,value);
engine.eval(scripteString,scops);
重定向输入和输出
StringWriter writer = new StringWriter()
engine.getContext().setWriter(new PrintWriter(writer));
通过上面的设置,脚本的pringt
和println
函数产生的输出都将输出到writer。
调用脚本的函数和方法
如果脚本引擎实现了Involcable
接口,那么我们可以这样来调用脚本函数:
if (enging instanceof Invocable){
enging.eval(reader);
Invocable invocable = (Invocable)engine;
Object result = (String)invocable.invokeFunction(methodName, param1,param2);
}
如果脚本语言是面向对象的,那么我们可以这样来调用:
var Tools = {
createNew: function () {
var tools = {};
tools.plus = function (a, b) {
return a + b;
}
return tools;
}
};
Tools.createNew();
Reader reader = new FileReader("script.js");
ScriptEngine jsEngien = Chapter2_10.getEngine("js");
if (jsEngien instanceof Invocable){
Object tool = jsEngien.eval(reader);//获取脚本对象的代理
Util.info(((Invocable)jsEngien).invokeMethod(tool,"plus",1,2));
}
invokeMethod
方法的第一个入参是脚本语言编写的对象的一个代理,它必须是前一个对脚本引擎调用的结果。
我们还可以通过Java接口来调用脚本函数:
我们先定义接口:
public interface Tools{
int plus(int a, int b);
}
然后我们在脚本中实现对应的方法:
function plus(a,b){
return a+b;
}
jsEngien.eval(reader);
Tools tools = ((Invocable)jsEngien).getInterface(Tools.class);
int result = tools.plus(1,2);
编译脚本
如果一个脚本需要被重复的执行,那么我们可以将脚本代码编译为某种中间格式,以提高程序的执行效率。
CompiledScript script = null;
if (engine instanceof Compilable){
script = ((Compilaable)engine).compile(reader);
}
if(script != null){
script.eval();
...
}else{
engine.eval();
...
}
注解
在Java中,注解被当做 修饰符 来使用的,它被置于被注解项之前,中间没有分号。注解项可以是类、方法、域或者局部变量,这些注解可以被放置在任何一个可以放置想public
或者static
这样的修饰符的地方。
每个注解都必须通过一个 注解接口 进行定义。这些接口中的方法与注解中的元素相对应。如:
@Target(ElementType.METHOD)
@Retention(RetentionPlicy.RUNTIME)
public @interface Test{
...
long timeout() default 0L;
}
-
@interface
:声明创建了一个真正的Java接口。处理注解的工具将接收那些实现了该注解接口的对象。 -
timeout()
:处理接口的工具可以调用该方法来检索某个特定Test注解的timeout元素。 -
Target(ElementType.METHOD)
:定义该注解只能用于注解方法 -
Retention(RetentionPlicy.RUNTIME)
:当类文件加载到虚拟机时,被注解的方法任被保留。
注解语法
注解是由 注解接口(@interface
) 定义的,每个元素声明都具有下面这种格式:
type elementName();
或者:
type elementName() default value();
(未完待续。。。)