`
samwong
  • 浏览: 281854 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JAVA嵌入运行Groovy脚本

 
阅读更多

最近设计一个数据统计系统,系统中上百种数据统计维度,而且这些数据统计的指标可能随时会调整.如果基于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) 简单的表达式执行,方法调用

Java代码收藏代码
  1. /**
  2. *简答脚本执行
  3. *@throwsException
  4. */
  5. publicstaticvoidevalScriptText()throwsException{
  6. //groovy.lang.Binding
  7. Bindingbinding=newBinding();
  8. GroovyShellshell=newGroovyShell(binding);
  9. binding.setVariable("name","zhangsan");
  10. shell.evaluate("println'HelloWorld!Iam'+name;");
  11. //在script中,声明变量,不能使用def,否则scrope不一致.
  12. shell.evaluate("date=newDate();");
  13. Datedate=(Date)binding.getVariable("date");
  14. System.out.println("Date:"+date.getTime());
  15. //以返回值的方式,获取script内部变量值,或者执行结果
  16. //一个shell实例中,所有变量值,将会在此"session"中传递下去."date"可以在此后的script中获取
  17. Longtime=(Long)shell.evaluate("deftime=date.getTime();returntime;");
  18. System.out.println("Time:"+time);
  19. binding.setVariable("list",newString[]{"A","B","C"});
  20. //invokemethod
  21. StringjoinString=(String)shell.evaluate("defcall(){returnlist.join('-')};call();");
  22. System.out.println("Arrayjoin:"+joinString);
  23. shell=null;
  24. binding=null;
  25. }

2) 伪main方法执行.

Java代码收藏代码
  1. /**
  2. *当groovy脚本,为完整类结构时,可以通过执行main方法并传递参数的方式,启动脚本.
  3. */
  4. publicstaticvoidevalScriptAsMainMethod(){
  5. String[]args=newString[]{"Zhangsan","10"};//main(String[]args)
  6. Bindingbinding=newBinding(args);
  7. GroovyShellshell=newGroovyShell(binding);
  8. shell.evaluate("staticvoidmain(String[]args){if(args.length!=2)return;println('Hello,Iam'+args[0]+',age'+args[1])}");
  9. shell=null;
  10. binding=null;
  11. }

3) 通过Shell运行具有类结构的Groovy脚本

Java代码收藏代码
  1. /**
  2. *运行完整脚本
  3. *@throwsException
  4. */
  5. publicstaticvoidevalScriptTextFull()throwsException{
  6. StringBufferbuffer=newStringBuffer();
  7. //defineAPI
  8. buffer.append("classUser{")
  9. .append("Stringname;Integerage;")
  10. //.append("User(Stringname,Integerage){this.name=name;this.age=age};")
  11. .append("StringsayHello(){return'Hello,Iam'+name+',age'+age;}}\n");
  12. //Usage
  13. buffer.append("defuser=newUser(name:'zhangsan',age:1);")
  14. .append("user.sayHello();");
  15. //groovy.lang.Binding
  16. Bindingbinding=newBinding();
  17. GroovyShellshell=newGroovyShell(binding);
  18. Stringmessage=(String)shell.evaluate(buffer.toString());
  19. System.out.println(message);
  20. //重写main方法,默认执行
  21. StringmainMethod="staticvoidmain(String[]args){defuser=newUser(name:'lisi',age:12);print(user.sayHello());}";
  22. shell.evaluate(mainMethod);
  23. shell=null;
  24. }

4) 方法执行和分部调用

Java代码收藏代码
  1. /**
  2. *以面向"过程"的方式运行脚本
  3. *@throwsException
  4. */
  5. publicstaticvoidevalScript()throwsException{
  6. Bindingbinding=newBinding();
  7. GroovyShellshell=newGroovyShell(binding);
  8. //直接方法调用
  9. //shell.parse(newFile(//))
  10. Scriptscript=shell.parse("defjoin(String[]list){returnlist.join('--');}");
  11. StringjoinString=(String)script.invokeMethod("join",newString[]{"A1","B2","C3"});
  12. System.out.println(joinString);
  13. ////脚本可以为任何格式,可以为main方法,也可以为普通方法
  14. //1)defcall(){...};call();
  15. //2)call(){...};
  16. script=shell.parse("staticvoidmain(String[]args){i=i*2;}");
  17. script.setProperty("i",newInteger(10));
  18. script.run();//运行,
  19. System.out.println(script.getProperty("i"));
  20. //thesameas
  21. System.out.println(script.getBinding().getVariable("i"));
  22. script=null;
  23. shell=null;
  24. }

二. GroovyClassLoader代码示例

1) 解析groovy文件

Java代码收藏代码
  1. /**
  2. *fromsourcefileof*.groovy
  3. */
  4. publicstaticvoidparse()throwsException{
  5. GroovyClassLoaderclassLoader=newGroovyClassLoader(Thread.currentThread().getContextClassLoader());
  6. FilesourceFile=newFile("D:\\TestGroovy.groovy");
  7. ClasstestGroovyClass=classLoader.parseClass(newGroovyCodeSource(sourceFile));
  8. GroovyObjectinstance=(GroovyObject)testGroovyClass.newInstance();//proxy
  9. Longtime=(Long)instance.invokeMethod("getTime",newDate());
  10. System.out.println(time);
  11. Datedate=(Date)instance.invokeMethod("getDate",time);
  12. System.out.println(date.getTime());
  13. //here
  14. instance=null;
  15. testGroovyClass=null;
  16. }

2) 如何加载已经编译的groovy文件(.class)

Java代码收藏代码
  1. publicstaticvoidload()throwsException{
  2. GroovyClassLoaderclassLoader=newGroovyClassLoader(Thread.currentThread().getContextClassLoader());
  3. BufferedInputStreambis=newBufferedInputStream(newFileInputStream("D:\\TestGroovy.class"));
  4. ByteArrayOutputStreambos=newByteArrayOutputStream();
  5. for(;;){
  6. inti=bis.read();
  7. if(i==-1){
  8. break;
  9. }
  10. bos.write(i);
  11. }
  12. ClasstestGroovyClass=classLoader.defineClass(null,bos.toByteArray());
  13. //instanceofproxy-class
  14. //ifinterfaceAPIisintheclasspath,youcandosuchas:
  15. //MyObjectinstance=(MyObject)testGroovyClass.newInstance()
  16. GroovyObjectinstance=(GroovyObject)testGroovyClass.newInstance();
  17. Longtime=(Long)instance.invokeMethod("getTime",newDate());
  18. System.out.println(time);
  19. Datedate=(Date)instance.invokeMethod("getDate",time);
  20. System.out.println(date.getTime());
  21. //here
  22. bis.close();
  23. bos.close();
  24. instance=null;
  25. testGroovyClass=null;
  26. }

三. ScriptEngine

1) pom.xml依赖

Xml代码收藏代码
  1. <dependency>
  2. <groupId>org.codehaus.groovy</groupId>
  3. <artifactId>groovy</artifactId>
  4. <version>2.1.6</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.codehaus.groovy</groupId>
  8. <artifactId>groovy-jsr223</artifactId>
  9. <version>2.1.6</version>
  10. </dependency>

2) 代码样例

Java代码收藏代码
  1. publicstaticvoidevalScript()throwsException{
  2. ScriptEngineManagerfactory=newScriptEngineManager();
  3. //每次生成一个engine实例
  4. ScriptEngineengine=factory.getEngineByName("groovy");
  5. System.out.println(engine.toString());
  6. assertengine!=null;
  7. //javax.script.Bindings
  8. Bindingsbinding=engine.createBindings();
  9. binding.put("date",newDate());
  10. //如果script文本来自文件,请首先获取文件内容
  11. engine.eval("defgetTime(){returndate.getTime();}",binding);
  12. engine.eval("defsayHello(name,age){return'Hello,Iam'+name+',age'+age;}");
  13. Longtime=(Long)((Invocable)engine).invokeFunction("getTime",null);
  14. System.out.println(time);
  15. Stringmessage=(String)((Invocable)engine).invokeFunction("sayHello","zhangsan",newInteger(12));
  16. System.out.println(message);
  17. }

需要提醒的是,在groovy中,${expression} 将会被认为一个变量,如果需要输出"$"符号,需要转义为"\$".

关于ScriptEngine更多介绍,请参考.

分享到:
评论
1 楼 相约的旋律 2015-12-10  
能把代码弄整齐不?

相关推荐

Global site tag (gtag.js) - Google Analytics