java代码中使用Groovy的三种方式详解

2024-01-03 16:42:17

java代码中使用Groovy

? Groovy语言是一种运行在java虚拟机上的一种动态语言,它可以单独使用,也可以配合java语言一起使用,下面的部分,我们将用java项目结合Groovy做一些学习和使用。

? 先建一个springboot项目,在项目中添加Groovy的依赖,本次演示使用的是groovy3.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脚本

? 通过GroovyShellevaluate方法执行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.groovyclass文件,文件的内容如下:

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.groovyGroovy_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.groovyGroovy_07.groovy两个脚本都可以正常的执行。
整个项目的代码结构如下:
在这里插入图片描述

文章来源:https://blog.csdn.net/qq_36305027/article/details/135365928
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。