您的位置:首页 > 编程语言 > Java开发

Java中使用Groovy的三种方式

2015-06-11 11:57 861 查看
一直想抽些时间回顾一下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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  groovy