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
相关推荐
花生了什么事o4 分钟前
DDD:领域驱动设计的初步认识
java·数据库
BGK11235815 分钟前
基于qemu_v8+optee 4.00 平台构建 ca/ta
java·大数据·数据库
Android洋芋31 分钟前
AI辅助C盘清理
c语言·开发语言·人工智能·ai辅助c盘清理
何中应1 小时前
Spring Boot整合Doris
java·数据库·spring boot
笨笨饿1 小时前
101_详解USB协议
java·jvm·数据结构
遨游DATA1 小时前
Maven dependencyManagement 已声明却仍缺 Jar:如何验证最终运行包
java·spring boot·maven·故障排查·依赖管理
腻害兔1 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 认证与权限:RBAC + 数据权限,这套“门禁系统“到底怎么设计的?
java·vue.js·人工智能·产品经理·ai编程
Summer-Bright2 小时前
深度 | Agent 协议标准化:一场决定了 AI 经济底层规则的基础设施战争
java·数据库·人工智能·ai
我叫张小白。2 小时前
LangChain 结构化输出(Structured Output)技术文档
java·数据库·langchain
灯澜忆梦2 小时前
Go 语言 _JSON---序列化与反序列化
开发语言·golang·json