Java 调用 Groovy 脚本的简单案例

Java 调用 Groovy 脚本的简单案例

前言

GroovyJava 都是使用 JVM 虚拟机进行解释执行的。工作中会遇到一些场景,需要对特殊的业务进行解耦。那段业务可能会经常变动,如果直接在Java代码里写业务的话就会涉及频繁的发包服务重启这类情况,那么如果我门把那段业务变成脚本的形式,单独做一个界面把它做成类似可以在线配置更改的情况,那么业务变动后直接在线改代码,而且立刻生效,这样是不是就特别方便。例如定时任务里的xxx-job也有这样的功能,我在以往的项目中也遇到过有人使用这种方式来解决这类问题,当年年少只是感叹他的神奇并没有尝试探索,这次抽空了解了下发现其实也不是很难,记录一下。

(一) 依赖

xml 复制代码
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
       <!-- groovy-all 这个是核心 版本号根据具体情况使用 -->
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.4.16</version>
        </dependency>

(二)Groovy脚本

Groovy 脚本最好还是在IDEA里提前写好,然后粘过去,IDEA有代码提示和语法提示写起来很方便,少踩坑

groovy 复制代码
def execute(paramModel) {
    def dateTime = paramModel.get('dateTime')
    def msg = paramModel.get('msg')
    def user = paramModel.get('user')
    println("now dateTime is:" + dateTime)
    println("message is:" + msg)
    println("user is:" + paramModel.get('user'))

    def a = 5
    def b = 3
    def c = '我是一个字符串用于进行拼接: '
    def result = a + b * 3 + dateTime.getYear()
    def str = c.concat(msg).concat(",").concat(user.getName())

    println("result: " + result)
    println("str: " + str)
    return user.toString()
}
execute(paramModel)

(三) 单元测试代码

入参假设是一个HashMap的这类对象,可以存放多个入参。这个 script,可以是从数据库里读取出来的脚本,也就是我们线上修改后的业务。执行具体业务的时候,服务代码里只要从库里读取这个脚本,只要不涉及参数的新增和参数名(key)的修改,其它代码都不需要进行变动就能正常执行了。

java 复制代码
/**
 * 脚本执行测试
 *
 * @author lv
 * @date 2024/03/14
 */
@Slf4j
@SpringBootTest
public class GroovyScriptTest {

    @Resource
    private BeanConfig.User user;

    /**
     * Java 调用groovy脚本的 示范案例,下面是某次的执行结果
     * now dateTime is: 2024-03-14T16:01:27.966835100
     * message is: 你好世界
     * user is: BeanConfig.User(name=lzb, birthday=2000-01-15T23:45, height=180)
     * result=> 2038
     * str=> 我是一个字符串用于进行拼接: 你好世界,lzb
     * 2038
     */
    @Test
    void simple() {
        // 这个 script 可以是从数据库中读取出来,得是下面的格式
        final String script = "def execute(paramModel) {\n" +
                "    def dateTime = paramModel.get('dateTime')\n" +
                "    def msg = paramModel.get('msg')\n" +
                "    def user = paramModel.get('user')\n" +
                "    println(\"now dateTime is: \" + dateTime)\n" +
                "    println(\"message is: \" + msg)\n" +
                "    println(\"user is: \" + paramModel.get('user'))\n" +
                "\n" +
                "    def a = 5\n" +
                "    def b = 3\n" +
                "    def c = '我是一个字符串用于进行拼接: '\n" +
                "    def result = a + b * 3 + dateTime.getYear()\n" +
                "    def str = c.concat(msg).concat(\",\").concat(user.getName())\n" +
                "\n" +
                "    println(\"result=> \" + result)\n" +
                "    println(\"str=> \" + str)\n" +
                "    return result\n" +
                "}\n" +
                "execute(paramModel)\n";
        // 构造函数的使用参数
        Map<String, Object> param = new HashMap<>();
        param.put("dateTime", LocalDateTime.now());
        param.put("msg", "你好世界");
        param.put("user", user);
        // 绑定参数
        Binding bind = new Binding();
        bind.setProperty("paramModel", param);
        // 执行groovy脚本获取结果
        GroovyShell groovyShell = new GroovyShell(bind);
        Object result = groovyShell.evaluate(script);
        System.out.println(result);
    }
}

被Spring管理的 User 配置类

java 复制代码
@Configuration
public class BeanConfig {

    @Data
    public static class User implements Serializable {
        private String name;
        private LocalDateTime birthday;
        private int height;
    }

    @Bean
    public User user() {
        User user = new User();
        user.setName("lzb");
        user.setHeight(180);
        user.setBirthday(LocalDateTime.of(2000, 1, 15, 23, 45));
        return user;
    }
}

参考资料

  • Chart GPT
相关推荐
布谷歌3 分钟前
Oops! 更改field的数据类型,影响到rabbitmq消费了...(有关于Java序列化)
java·开发语言·分布式·rabbitmq·java-rabbitmq
PXM的算法星球4 分钟前
java(spring boot)实现向deepseek/GPT等模型的api发送请求/多轮对话(附源码)
java·gpt·microsoft
被程序耽误的胡先生8 分钟前
java中 kafka简单应用
java·开发语言·kafka
刀客1239 分钟前
python小项目编程-中级(1、图像处理)
开发语言·图像处理·python
卷卷的小趴菜学编程13 分钟前
c++之多态
c语言·开发语言·c++·面试·visual studio code
F202269748620 分钟前
Spring MVC 对象转换器:初级开发者入门指南
java·spring·mvc
冷琴199633 分钟前
基于Python+Vue开发的反诈视频宣传管理系统源代码
开发语言·vue.js·python
楠枬41 分钟前
网页五子棋——对战后端
java·开发语言·spring boot·websocket·spring
kyle~43 分钟前
thread---基本使用和常见错误
开发语言·c++·算法