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
相关推荐
zhangfeng11332 小时前
openclaw skills 小龙虾技能 通讯仿真 matlab skill Simulink Agentic Toolkit,通过kimi找到,mcp通讯
开发语言·matlab·openclaw·通讯仿真
Javatutouhouduan8 小时前
2026Java面试的正确打开方式!
java·高并发·java面试·java面试题·后端开发·java编程·java八股文
chao1898448 小时前
基于 SPEA2 的多目标优化算法 MATLAB 实现
开发语言·算法·matlab
JAVA面经实录9178 小时前
Java初级最终完整版学习路线图
java·spring·eclipse·maven
赏金术士9 小时前
Kotlin 习题集 · 高级篇
android·开发语言·kotlin
Cat_Rocky9 小时前
k8s-持久化存储,粗浅学习
java·学习·kubernetes
楼兰公子10 小时前
buildroot 在编译rust时裁剪平台类型数量的方法
开发语言·后端·rust
知识领航员10 小时前
蘑兔AI音乐深度实测:功能拆解、实测表现与适用场景
java·c语言·c++·人工智能·python·算法·github
吴声子夜歌10 小时前
Go——并发编程
开发语言·后端·golang
释怀°Believe10 小时前
Spring解析
java·后端·spring