Java中使用Groovy的三种方式 - Go语言中文社区

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.基本特性

(1). 构建在强大的Java语言之上 并 添加了从Python,Ruby和Smalltalk等语言中学到的 诸多特征,例如动态类型转换、闭包和元编程(metaprogramming)支持。。
(2).为Java开发者提供了 现代最流行的编程语言特性,而且学习成本很低(几乎为零)。
(3). 支持DSL(Domain Specific Languages领域定义语言)和其它简洁的语法,让代码变得易于阅读和维护。
(4).受检查类型异常(Checked Exception)也可以不用捕获。
(5). Groovy拥有处理原生类型,面向对象以及一个Ant DSL,使得创建Shell Scripts变得非常简单。
(6).在开发Web,GUI,数据库或控制台程序时 通过 减少框架性代码 大大提高了开发者的效率。
(7).支持单元测试和模拟(对象),可以 简化测试。
(8).无缝集成 所有已经存在的 Java对象和类库。
(9).直接编译成Java字节码,这样可以在任何使用Java的地方 使用Groovy。
(10).支持函数式编程,不需要main函数。
(11).一些新的运算符。
(12).默认导入常用的包。
(13).断言不支持jvm的-ea参数进行开关。
(14).支持对对象进行布尔求值。
(15).类不支持default作用域,且默认作用域为public。
(16).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

package com.juxinli.groovy.shell

def sayHello(String name) {
	println "Hello, " + name
	
	"GroovyShell_3_1中的sayHello()方法的返回值"
}

sayHello(name)
GroovyShell_3_1.groovy


package com.juxinli.groovy.shell

def sayHello(String name) {
	println "你好, " + name
	
	"GroovyShell_3_2中的sayHello()方法的返回值"
}

sayHello(name)
GroovyShell_3_2.groovy


package com.juxinli.groovy.shell

def sayHello(String name) {
	println "Привет, " + name
	
	"GroovyShell_3_3中的sayHello()方法的返回值"
}

// 运行groovy方法
sayHello(name)
GroovyShell_3_3.groovy

使用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的三种方式


GitHub下载地址

https://github.com/leonzm/java_groovy.git


参考&引用:

Groovy百度百科

Groovy入门教程
Groovy在线文档

groovy 三种运用

java中直接调用groovy的类

在Java里整合Groovy脚本的一个陷阱

Groovy深入探索——Groovy的ClassLoader体系

ClassLoader 详解及用途(写的不错)

Java中运行动态脚本 如Groovy


版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/iteye_2022/article/details/82635970
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-05-30 17:28:08
  • 阅读 ( 906 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢