Java中使用Groovy的三种方式
一直想抽些时间回顾一下Groovy,非常感谢Groovy,虽然只使用了其很小一部分功能,却给项目运行带来了极大的便利。该博客用于帮助那些需要在Java中集成Groovy的童鞋们。
一.Groovy简单了解
1.简介
Groovy 是 用于Java虚拟机的一种敏捷的动态语言,它是一种成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言。使用该种语言不必编写过多的代码,同时又具有闭包和动态语言中的其他特性。
Groovy是JVM的一个替代语言(替代是指可以用 Groovy 在Java平台上进行 Java 编程),使用方式基本与使用 Java代码的方式相同,该语言特别适合与Spring的动态语言支持一起使用,设计时充分考虑了Java集成,这使Groovy 与 Java 代码的互操作很容易。(注意:不是指Groovy替代java,而是指Groovy和java很好的结合编程。
有人说,Groovy 是下一代的Java语言,不是说Groovy会替代Java,读者如果看过Java8 之 lambda表达式 与 Stream,不难发现lambda和Groovy中的闭包非常相似,Stream也融入了Groovy的思想,所以Java会越来越像Groovy。
2.基本特性
- 构建在强大的Java语言之上 并 添加了从Python,Ruby和Smalltalk等语言中学到的 诸多特征,例如动态类型转换、闭包和元编程(metaprogramming)支持。。
- 为Java开发者提供了 现代最流行的编程语言特性,而且学习成本很低(几乎为零)。
- 支持DSL(Domain Specific Languages领域定义语言)和其它简洁的语法,让代码变得易于阅读和维护。
- 受检查类型异常(Checked Exception)也可以不用捕获。
- Groovy拥有处理原生类型,面向对象以及一个Ant DSL,使得创建Shell Scripts变得非常简单。
- 在开发Web,GUI,数据库或控制台程序时 通过 减少框架性代码 大大提高了开发者的效率。
- 支持单元测试和模拟(对象),可以 简化测试。
- 无缝集成 所有已经存在的 Java对象和类库。
- 直接编译成Java字节码,这样可以在任何使用Java的地方 使用Groovy。
- 支持函数式编程,不需要main函数。
- 一些新的运算符。
- 默认导入常用的包。
- 断言不支持jvm的-ea参数进行开关。
- 支持对对象进行布尔求值。
- 类不支持default作用域,且默认作用域为public。
- groovy中基本类型也是对象,可以直接调用对象的方法。
二.Java中使用Groovy的三种方式
注:该Maven项目需要加入groovy-all包的依赖,这里使用的是最新的2.4.3版本。Eclipse中最好安装groovy的插件,便于调试。
1.使用GroovyShell执行groovy脚本
(1). 通过evaluate方法执行groovy片段
GroovyShell类提供一个evaluate方法,可直接运行一段字符串标示的groovy片段,如
// 调用evaluate方法直接执行一段Groovy
public static void testGroovy1() throws CompilationFailedException, IOException {
GroovyShell groovyShell = new GroovyShell();
groovyShell.evaluate("println 'My First Groovy shell.'");
}
运行该方法输出如下:
My First Groovy shell.
是不是很方便,GroovyShell的evaluate方法非常类似于Js的eva方法,可执行一段字符串。
(2).通过evaluate方法调用groovy脚本文件
首先新建一个Groovy文件:GroovyShell_1_1.groovy,里面有一个无参的方法sayHello,并在最后调用该方法。
// 不带参数的groovy方法
def sayHello() {
println 'Hello World.'
// 如果不写return, groovy方法的默认最后一行为 方法的返回值
//return "GroovyShell_1中的sayHello()方法的返回值"
"GroovyShell_1中的sayHello()方法的返回值"
}
// 运行groovy方法
sayHello()
在Java中就可以直接调用这个groovy文件执行了,方法如下:
// 调用GroovyShell_1_1
public static void testGroovy2() throws CompilationFailedException, IOException {
GroovyShell groovyShell = new GroovyShell();
Object result = groovyShell.evaluate(new File("src/main/java/com/juxinli/groovy/GroovyShell_1_1.groovy"));
logger.info(result.toString());
}
运行结果如下:
Hello World.
2015-06-10 18:23:27 [main] INFO tool.Tool_GroovyShell_1 : GroovyShell_1中的sayHello()方法的返回值
第一行是 方法sayHello输出的,第二行是sayHello方法的返回值. 当然,你可以传一个参数给Groovy文件并执行,新建GroovyShell_1_1.groovy,提供一个传参的sayHello方法,如:
// 带参数的groovy方法
def sayHello(name) {
println "Hello " + name + "."
// 如果不写return, groovy方法的默认最后一行为 方法的返回值
//return "GroovyShell_1中的sayHello()方法的返回值"
"GroovyShell_1中的sayHello(name)方法的返回值"
}
// 运行groovy方法
sayHello(name)
在Java中使用Groovy提供的Binding类来绑定参数
// 调用GroovyShell_1_2
public static void testGroovy3() throws CompilationFailedException, IOException {
// 调用带参数的groovy shell时,使用bind绑定数据
Binding binding = new Binding();
binding.setProperty("name", "Juxinli");
GroovyShell groovyShell = new GroovyShell(binding);
Object result = groovyShell.evaluate(new File("src/main/java/com/juxinli/groovy/GroovyShell_1_2.groovy"));
logger.info(result.toString());
}
运行结果如下:
Hello Juxinli.
2015-06-10 18:30:01 [main] INFO tool.Tool_GroovyShell_1 : GroovyShell_1中的sayHello(name)方法的返回值
是不是很简单 ,但evaluate方法提供的作用不止这些,查官方API你会发现. evaluate方法还可以执行GroovyCodeSource(Groovy提供的包装类),或者 从互联网上执行一段脚本,还可以从输入流来执行相应的groovy等等。种类很多,大家有兴趣可以去研究。
2. 通过GroovyClassLoader动态加载Groovy Class
我们比较熟悉Java的ClassLoader类加载器,当运行Java程序时,首先运行JVM(Java虚拟机),然后再把Java class加载到JVM里头运行,负责加载Java class的这部分就叫做Class Loader。而GroovyClassLoader,顾名思义,就是用来加载Groovy类的加载器,想更深入了解,请参考Groovy深入探索——Groovy的ClassLoader体系。
通过GroovyClassLoader执行Groovy的方法如下:
首先新建了Groovy Class
package com.juxinli.groovy
class GroovyShell_2 {
public String sayHello(String name, String sex, int age) {
println 'GroovyShell_2 的sayHello(String name, String sex, int age)方法';
return "name: " + name + ", sex: " + sex + ", age: " + age;
}
}
在Tool_GroovyShell_2中就可以加载该Groovy Class了
public class Tool_GroovyShell_2 {
private static Logger logger = Logger.getLogger(Tool_GroovyShell_2.class);
private static GroovyClassLoader groovyClassLoader = null;
public static void initGroovyClassLoader() {
CompilerConfiguration config = new CompilerConfiguration();
config.setSourceEncoding("UTF-8");
// 设置该GroovyClassLoader的父ClassLoader为当前线程的加载器(默认)
groovyClassLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader(), config);
}
/**
* 通过GroovyClassLoader加载GroovyShell_2,并反射调用其sayHello(String name, String sex, int age)方法
*
*/
public static String invokeSayHello(String name, String sex, int age) {
String result = "";
File groovyFile = new File("src/main/java/com/juxinli/groovy/GroovyShell_2.groovy");
if (!groovyFile.exists()) {
return result;
}
try {
// 获得GroovyShell_2加载后的class
Class<?> groovyClass = groovyClassLoader.parseClass(groovyFile);
// 获得GroovyShell_2的实例
GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
// 反射调用sayHello方法得到返回值
Object methodResult = groovyObject.invokeMethod("sayHello", new Object[] {name, sex, age});
if (methodResult != null) {
result = methodResult.toString();
}
} catch (Exception e) {
logger.warn("加载groovy类失败", e);
}
return result;
}
public static void main(String[] args) throws Exception {
initGroovyClassLoader();
System.out.println(invokeSayHello("张三", "男", 25));
}
}
其方式和Java中类的加载反射类似,这里不再熬述。需要注意的是,GroovyClassLoader与Java中的加载器一样,同一个类名的类只能加载一次,如果想再次加载,必须调用GroovyClassLoader的clearCache()方法移除所有已经加载的Groovy Class,详细文档见 Groovy在线文档。
运行结果:
GroovyShell_2 的sayHello(String name, String sex, int age)方法
name: 张三, sex: 男, age: 25
第一行为GroovyShell_2.groovy的sayHello(...)方法中内部的输出,第二行为其返回的字符串。
3.使用GroovyScriptEngine脚本引擎加载Groovy脚本
GroovyScriptEngine从指定的位置(文件系统,URL,数据库等等)加载Groovy脚本,并且随着脚本变化可重新加载它们。和GroovyShell一样,GroovyScriptEngine也可以传进变量值返回脚本的计算结果。这样我们可以把一些可用的计算公式或计算条件写入Groovy脚本中来执行应用计算。当这些公式或计算条件变更时,我们可更方便地进行更改计算。
从文件夹中加载Groovy脚本的例子如下:
首先在com.juxinli.groovy.shell包中新建三个groovy script
GroovyShell_3_1.groovy
package com.juxinli.groovy.shell
def sayHello(String name) {
println "Hello, " + name
"GroovyShell_3_1中的sayHello()方法的返回值"
}
sayHello(name)
GroovyShell_3_2.groovy
package com.juxinli.groovy.shell
def sayHello(String name) {
println "你好, " + name
"GroovyShell_3_2中的sayHello()方法的返回值"
}
sayHello(name)
GroovyShell_3_3.groovy
package com.juxinli.groovy.shell
def sayHello(String name) {
println "Привет, " + name
"GroovyShell_3_3中的sayHello()方法的返回值"
}
// 运行groovy方法
sayHello(name)
使用GroovyScriptEngine从com.juxinli.groovy.shell包中加载、运行这些script
public class Tool_GroovyShell_3 {
public static void main(String[] args) throws Exception {
// GroovyScriptEngine的根路径,如果参数是字符串数组,说明有多个根路径
GroovyScriptEngine engine = new GroovyScriptEngine("src/main/java/com/juxinli/groovy/shell/");
//GroovyScriptEngine engine = new GroovyScriptEngine(new String[] {"src/main/java/com/juxinli/groovy/shell/"});
Binding binding = new Binding();
binding.setVariable("name", "juxinli");
Object result1 = engine.run("GroovyShell_3_1.groovy", binding);
System.out.println(result1);
Object result2 = engine.run("GroovyShell_3_2.groovy", binding);
System.out.println(result2);
Object result3 = engine.run("GroovyShell_3_3.groovy", binding);
System.out.println(result3);
}
}
运行结果:
Hello, juxinli
GroovyShell_3_1中的sayHello()方法的返回值
你好, juxinli
GroovyShell_3_2中的sayHello()方法的返回值
Привет, juxinli
GroovyShell_3_3中的sayHello()方法的返回值
GroovyScriptEngine的构造的方法有很多,可以参考 Groovy在线文档
粗浅的回顾了一下,发现还有很多可以深入的地方,大家有好的 Groovy 应用 与发现,欢迎一起讨论、学习。
附源码下载:
java_groovy项目
csdn下载地址
Java中使用Groovy的三种方式http://download.csdn.net/detail/a906998248/8795483
GitHub下载地址
https://github.com/leonzm/java_groovy.git
参考&引用:
- Groovy百度百科http://baike.baidu.com/link?url=Y2BOwTV4Y6h-Th3SajQNvcHBFMBj4UjxHrstWPyR6H9lMQ-HuRqN0jbPZbF6oh8Ph39fygMMFUdMoGZeDDOH_a
- Groovy入门教程http://blog.csdn.net/kmyhy/article/details/4200563
- Groovy在线文档http://tool.oschina.net/apidocs/apidoc?api=groovy
- groovy 三种运用http://blog.csdn.net/zj7758/article/details/8313034
- java中直接调用groovy的类http://blog.csdn.net/fei33423/article/details/24207703
- 在Java里整合Groovy脚本的一个陷阱http://rednaxelafx.iteye.com/blog/620155
- Groovy深入探索——Groovy的ClassLoader体系http://johnnyjian.iteye.com/blog/1847151
- ClassLoader 详解及用途(写的不错)http://blog.chinaunix.net/uid-21227800-id-65885.html
- Java中运行动态脚本 如Groovyhttp://www.360doc.com/content/14/0513/14/16002580_377222883.shtml
本文由 创作,采用 知识共享署名4.0 国际许可协议进行许可。本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。最后编辑时间为: 2021/11/23 02:15