java代码中使用Groovy
Groovy
语言是一种运行在java
虚拟机上的一种动态语言,它可以单独使用,也可以配合java
语言一起使用,下面的部分,我们将用java
项目结合Groovy
做一些学习和使用。
先建一个springboot
项目,在项目中添加Groovy
的依赖,本次演示使用的是groovy
的3.0.20
版本:
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>3.0.20</version>
</dependency>
在java
中使用Groovy
有三种方式:通过GroovyShell
执行Groovy
脚本;通过GroovyClassLoader
动态加载Groovy Class
文件;通过GroovyScriptEngine
脚本引擎加载Groovy
脚本。
1 GroovyShell
执行Groovy
脚本
通过GroovyShell
的evaluate
方法执行Groovy
脚本,evaluate
方法的入参比较多,可以是一个字符串,也可以是一个文件流或者文件,下图是该方法的入参。
先通过一个简单的字符串脚本的执行来入门,下面代码就是在Groovy
脚本中打印一行字,其中cmd
代表需要执行的脚本,通过groovyShell.evaluate(cmd)
执行:
package com.dream21th.groovy;
import groovy.lang.GroovyShell;
public class Groovy_study01 {
public static void main(String[] args) {
String cmd="def name=\"张三\";\n" +
"println(\"my name is \"+ name)\n";
GroovyShell groovyShell = new GroovyShell();
Object evaluate = groovyShell.evaluate(cmd);
System.out.println("执行指令返回结果:"+evaluate);
}
}
接着来学习一下加载Groovy
脚本文件来执行脚本中的方法,脚本代码如下:
// 不带参数的groovy方法
def sayHello() {
println 'Hello Groovy'
// 如果不写return, groovy方法的默认最后一行为 方法的返回值
//return "Groovy_02中的sayHello()方法的返回值"
"Groovy_02.groovy中的sayHello()方法的返回值"
}
// 运行groovy方法
sayHello()
编写java
逻辑代码如下:
package com.dream21th.groovy;
import groovy.lang.GroovyShell;
import java.io.File;
import java.io.IOException;
public class Groovy_study02 {
public static void main(String[] args) throws IOException {
GroovyShell groovyShell = new GroovyShell();
Object evaluate = groovyShell.evaluate(new File("D:\\code\\study\\java\\java_groovy\\src\\main\\resources\\Groovy_02.groovy"));
System.out.println("代码执行结果:"+evaluate);
}
}
通过下面代码可以看出,在evaluate
方法的入参是一个文件,通过该方式可以执行脚本文件并返回脚本执行结果。
上面的例子介绍了如何执行脚本文件,这个例子介绍如何在脚本文件中添加参数,编写一个带有参数的方法的脚本,脚本的内容如下:
// 带参数的groovy方法
def sayHello(name, age) {
printf("my name is %s,i am %s year old \n",name,age)
// 如果不写return, groovy方法的默认最后一行为 方法的返回值
//return "Groovy_03中的sayHello()方法的返回值"
"Groovy_03.groovy中的sayHello(name, age)方法的返回值"
}
// 运行groovy方法
sayHello(name, age)
该脚本包含两个入参,下面编写执行该脚本的java
代码:
package com.dream21th.groovy;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import java.io.File;
import java.io.IOException;
public class Groovy_study03 {
public static void main(String[] args) throws IOException {
//调用带有入参的groovy脚本时,使用Binding进行参数传递
Binding binding = new Binding();
binding.setProperty("name","徐达");
binding.setProperty("age",18);
GroovyShell groovyShell = new GroovyShell(binding);
Object evaluate = groovyShell.evaluate(new File("D:\\code\\study\\java\\java_groovy\\src\\main\\resources\\Groovy_03.groovy"));
System.out.println("代码执行结果:"+evaluate);
}
}
在调用含有入参的脚本的时候,参数的传递是通过Binding
来辅助完成的。
2 GroovyClassLoader
动态加载Groovy Class
文件
除了执行Groovy
的脚本文件,还可以通过GroovyClassLoader
动态加载Groovy Class
文件,编写一个Groovy_04.groovy
的class文件:
class Groovy_04 {
String sayHello(name,age){
printf("my name is %s,i am %s year old \n",name,age)
return "my name is "+name+",i am "+age+"year old"
}
}
该文件包含一个sayHello(name,age)
方法,方法有两个入参,接着编写java
测试代码:
package com.dream21th.groovy;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import org.codehaus.groovy.control.CompilerConfiguration;
import java.io.File;
public class Groovy_study04 {
public static void main(String[] args) {
initGroovyClassLoader();
String result = invokeSayHello("李武", 18,"D:\\code\\study\\java\\java_groovy\\src\\main\\resources\\Groovy_04.groovy");
System.out.println("执行结果:"+result);
}
private static GroovyClassLoader groovyClassLoader = null;
//初始化GroovyClassLoader
public static void initGroovyClassLoader() {
CompilerConfiguration config = new CompilerConfiguration();
config.setSourceEncoding("UTF-8");
// 设置该GroovyClassLoader的父ClassLoader为当前线程的加载器(默认)
groovyClassLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader(), config);
}
/**
* 通过GroovyClassLoader加载Groovy_04.groovy,并反射调用其sayHello(name, age)方法
*/
public static String invokeSayHello(String name, int age,String filePath) {
String result = "";
File groovyFile = new File(filePath);
if (!groovyFile.exists()) {
return result;
}
try {
// 获得Groovy_04.groovy加载后的class
Class<?> groovyClass = groovyClassLoader.parseClass(groovyFile);
// 获得Groovy_04.groovy的实例
GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
// 反射调用sayHello方法得到返回值
Object methodResult = groovyObject.invokeMethod("sayHello", new Object[] {name,age});
if (methodResult != null) {
result = methodResult.toString();
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
通过反射调用Groovy_04.groovy
中的sayHello
方法,并传入参数,最终得到结果。
除了这个例子中使用的java
中的自带数据类型,还可以使用自定义的数据类型,接着看下面的例子,先定义一个Student
类,类的代码信息如下(包含两个属性):
package com.dream21th.groovy.dto;
public class Student {
private String name;
private Integer age;
public Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
我们编写Groovy_05.groovy
的class
文件,文件的内容如下:
import com.dream21th.groovy.dto.Student
class Groovy_05 {
String sayHello(Student student){
printf("my name is %s,i am %s year old \n",student.name,student.age)
return "my name is "+student.name+",i am "+student.age+"year old"
}
}
该类中的方法sayHello
包含自定义的Student
类,接下来编写测试代码:
package com.dream21th.groovy;
import com.dream21th.groovy.dto.Student;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import org.codehaus.groovy.control.CompilerConfiguration;
import java.io.File;
public class Groovy_study05 {
public static void main(String[] args) {
initGroovyClassLoader();
String result = invokeSayHello("D:\\code\\study\\java\\java_groovy\\src\\main\\resources\\Groovy_05.groovy","sayHello",new Object[]{new Student("张三",18)});
System.out.println("执行结果:"+result);
}
private static GroovyClassLoader groovyClassLoader = null;
//初始化GroovyClassLoader
public static void initGroovyClassLoader() {
CompilerConfiguration config = new CompilerConfiguration();
config.setSourceEncoding("UTF-8");
// 设置该GroovyClassLoader的父ClassLoader为当前线程的加载器(默认)
groovyClassLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader(), config);
}
/**
* 通过GroovyClassLoader加载Groovy_05.groovy,并反射调用其sayHello(student)方法
*/
public static String invokeSayHello(String filePath,String methodName,Object[] params) {
String result = "";
File groovyFile = new File(filePath);
if (!groovyFile.exists()) {
return result;
}
try {
// 获得Groovy_05.groovy加载后的class
Class<?> groovyClass = groovyClassLoader.parseClass(groovyFile);
// 获得Groovy_05.groovy的实例
GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
// 反射调用sayHello方法得到返回值
Object methodResult = groovyObject.invokeMethod(methodName, params);
if (methodResult != null) {
result = methodResult.toString();
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
通过反射调用sayHello
方法,并传入Student
类的实例,运行得到正确的结果。
3 GroovyScriptEngine
脚本引擎加载Groovy
脚本
除了上面的两种方式,还可以采用GroovyScriptEngine
脚本引擎加载Groovy
脚本的方式。编写Groovy_06.groovy
和Groovy_07.groovy
两个脚本,代码信息如下:
// 带参数的groovy方法
def sayHello(name, age) {
printf("my name is %s,i am %s year old \n",name,age)
// 如果不写return, groovy方法的默认最后一行为 方法的返回值
//return "Groovy_06中的sayHello()方法的返回值"
"Groovy_06.groovy中的sayHello(name, age)方法的返回值"
}
// 运行groovy方法
sayHello(name, age)
import com.dream21th.groovy.dto.Student
def sayHello(Student student){
printf("my name is %s,i am %s year old \n",student.name,student.age)
return "my name is "+student.name+",i am "+student.age+"year old"
}
sayHello(student)
两个脚本的主要差异在方法的入参上面,编写测试用的java
代码:
package com.dream21th.groovy;
import com.dream21th.groovy.dto.Student;
import groovy.lang.Binding;
import groovy.util.GroovyScriptEngine;
public class Groovy_study06 {
public static void main(String[] args) throws Exception {
// GroovyScriptEngine的根路径(目录),如果参数是字符串数组,说明有多个根路径
GroovyScriptEngine engine = new GroovyScriptEngine("D:\\code\\study\\java\\java_groovy\\src\\main\\resources");
Binding binding = new Binding();
binding.setVariable("name", "王三");
binding.setVariable("age",19);
binding.setVariable("student",new Student("无名",39));
Object result1 = engine.run("Groovy_06.groovy", binding);
System.out.println(result1);
Object result2 = engine.run("Groovy_07.groovy", binding);
System.out.println(result2);
}
}
需要注意的是,使用GroovyScriptEngine
加载脚本,指定的是文件夹,所以该文件夹下的所有脚本都可以执行,看上面的代码实例,Groovy_06.groovy
和Groovy_07.groovy
两个脚本都可以正常的执行。
整个项目的代码结构如下: