最近设计一个数据统计系统,系统中上百种数据统计维度,而且这些数据统计的指标可能随时会调整.如果基于java编码的方式逐个实现数据统计的API设计,工作量大而且维护起来成本较高;最终确定为将"数据统计"的计算部分单独分离成脚本文件(javascript,或者Groovy),非常便捷了实现了"数据统计Task" 与 "数据统计规则(计算)"解耦,且可以动态的加载和运行的能力.顺便对JAVA嵌入运行Groovy脚本做个备忘.
Java中运行Groovy,有三种比较常用的类支持:GroovyShell,GroovyClassLoader以及Java-Script引擎(JSR-223).
1) GroovyShell: 通常用来运行"script片段"或者一些零散的表达式(Expression)
2) GroovyClassLoader: 如果脚本是一个完整的文件,特别是有API类型的时候,比如有类似于JAVA的接口,面向对象设计时,通常使用GroovyClassLoader.
3) ScriptEngine: JSR-223应该是推荐的一种使用策略.规范化,而且简便.
一.GroovyShell代码样例
1) 简单的表达式执行,方法调用
-
-
-
-
- publicstaticvoidevalScriptText()throwsException{
-
- Bindingbinding=newBinding();
- GroovyShellshell=newGroovyShell(binding);
-
- binding.setVariable("name","zhangsan");
- shell.evaluate("println'HelloWorld!Iam'+name;");
-
- shell.evaluate("date=newDate();");
- Datedate=(Date)binding.getVariable("date");
- System.out.println("Date:"+date.getTime());
-
-
- Longtime=(Long)shell.evaluate("deftime=date.getTime();returntime;");
- System.out.println("Time:"+time);
- binding.setVariable("list",newString[]{"A","B","C"});
-
- StringjoinString=(String)shell.evaluate("defcall(){returnlist.join('-')};call();");
- System.out.println("Arrayjoin:"+joinString);
- shell=null;
- binding=null;
- }
2) 伪main方法执行.
-
-
-
- publicstaticvoidevalScriptAsMainMethod(){
- String[]args=newString[]{"Zhangsan","10"};
- Bindingbinding=newBinding(args);
- GroovyShellshell=newGroovyShell(binding);
- shell.evaluate("staticvoidmain(String[]args){if(args.length!=2)return;println('Hello,Iam'+args[0]+',age'+args[1])}");
- shell=null;
- binding=null;
- }
3) 通过Shell运行具有类结构的Groovy脚本
-
-
-
-
- publicstaticvoidevalScriptTextFull()throwsException{
- StringBufferbuffer=newStringBuffer();
-
- buffer.append("classUser{")
- .append("Stringname;Integerage;")
-
- .append("StringsayHello(){return'Hello,Iam'+name+',age'+age;}}\n");
-
- buffer.append("defuser=newUser(name:'zhangsan',age:1);")
- .append("user.sayHello();");
-
- Bindingbinding=newBinding();
- GroovyShellshell=newGroovyShell(binding);
- Stringmessage=(String)shell.evaluate(buffer.toString());
- System.out.println(message);
-
- StringmainMethod="staticvoidmain(String[]args){defuser=newUser(name:'lisi',age:12);print(user.sayHello());}";
- shell.evaluate(mainMethod);
- shell=null;
- }
4) 方法执行和分部调用
-
-
-
-
- publicstaticvoidevalScript()throwsException{
- Bindingbinding=newBinding();
- GroovyShellshell=newGroovyShell(binding);
-
-
- Scriptscript=shell.parse("defjoin(String[]list){returnlist.join('--');}");
- StringjoinString=(String)script.invokeMethod("join",newString[]{"A1","B2","C3"});
- System.out.println(joinString);
-
-
-
- script=shell.parse("staticvoidmain(String[]args){i=i*2;}");
- script.setProperty("i",newInteger(10));
- script.run();
- System.out.println(script.getProperty("i"));
-
- System.out.println(script.getBinding().getVariable("i"));
- script=null;
- shell=null;
- }
二. GroovyClassLoader代码示例
1) 解析groovy文件
-
-
-
- publicstaticvoidparse()throwsException{
- GroovyClassLoaderclassLoader=newGroovyClassLoader(Thread.currentThread().getContextClassLoader());
- FilesourceFile=newFile("D:\\TestGroovy.groovy");
- ClasstestGroovyClass=classLoader.parseClass(newGroovyCodeSource(sourceFile));
- GroovyObjectinstance=(GroovyObject)testGroovyClass.newInstance();
- Longtime=(Long)instance.invokeMethod("getTime",newDate());
- System.out.println(time);
- Datedate=(Date)instance.invokeMethod("getDate",time);
- System.out.println(date.getTime());
-
- instance=null;
- testGroovyClass=null;
- }
2) 如何加载已经编译的groovy文件(.class)
- publicstaticvoidload()throwsException{
- GroovyClassLoaderclassLoader=newGroovyClassLoader(Thread.currentThread().getContextClassLoader());
- BufferedInputStreambis=newBufferedInputStream(newFileInputStream("D:\\TestGroovy.class"));
- ByteArrayOutputStreambos=newByteArrayOutputStream();
- for(;;){
- inti=bis.read();
- if(i==-1){
- break;
- }
- bos.write(i);
- }
- ClasstestGroovyClass=classLoader.defineClass(null,bos.toByteArray());
-
-
-
- GroovyObjectinstance=(GroovyObject)testGroovyClass.newInstance();
- Longtime=(Long)instance.invokeMethod("getTime",newDate());
- System.out.println(time);
- Datedate=(Date)instance.invokeMethod("getDate",time);
- System.out.println(date.getTime());
-
-
- bis.close();
- bos.close();
- instance=null;
- testGroovyClass=null;
- }
三. ScriptEngine
1) pom.xml依赖
- <dependency>
- <groupId>org.codehaus.groovy</groupId>
- <artifactId>groovy</artifactId>
- <version>2.1.6</version>
- </dependency>
- <dependency>
- <groupId>org.codehaus.groovy</groupId>
- <artifactId>groovy-jsr223</artifactId>
- <version>2.1.6</version>
- </dependency>
2) 代码样例
- publicstaticvoidevalScript()throwsException{
- ScriptEngineManagerfactory=newScriptEngineManager();
-
- ScriptEngineengine=factory.getEngineByName("groovy");
- System.out.println(engine.toString());
- assertengine!=null;
-
- Bindingsbinding=engine.createBindings();
- binding.put("date",newDate());
-
- engine.eval("defgetTime(){returndate.getTime();}",binding);
- engine.eval("defsayHello(name,age){return'Hello,Iam'+name+',age'+age;}");
- Longtime=(Long)((Invocable)engine).invokeFunction("getTime",null);
- System.out.println(time);
- Stringmessage=(String)((Invocable)engine).invokeFunction("sayHello","zhangsan",newInteger(12));
- System.out.println(message);
- }
需要提醒的是,在groovy中,${expression} 将会被认为一个变量,如果需要输出"$"符号,需要转义为"\$".
关于ScriptEngine更多介绍,请参考.