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
相关推荐
kyriewen114 分钟前
为什么我的代码在测试环境跑得好好的,一到用户电脑就崩?原来凶手躲在地址栏旁边
开发语言·前端·javascript·chrome·ecmascript·html5
YMWM_14 分钟前
python3中的装饰器介绍及其应用场景
java·后端·spring
sheji341615 分钟前
【开题答辩全过程】以 基于Java的饮品店管理系统的实现为例,包含答辩的问题和答案
java·开发语言
大阿明18 分钟前
Spring.factories
java·数据库·spring
暴躁小师兄数据学院18 分钟前
【WEB3.0零基础转行笔记】go编程篇-第12讲:go-zero入门实战
开发语言·笔记·golang·web3·区块链
菜鸟程序员专写BUG20 分钟前
SpringBoot 事务失效报错全集|rollback不生效/事务不回滚/传播机制踩坑全解决
java·spring boot·spring
小北方城市网23 分钟前
JavaScript 实战 —— 实现一个简易的 TodoList(适合前端入门 / 进阶)
开发语言·前端·javascript
向上_5035829126 分钟前
配置Protobuf输出Java文件或kotlin文件
android·java·开发语言·kotlin
njidf28 分钟前
C++中的观察者模式
开发语言·c++·算法
IAUTOMOBILE29 分钟前
C++ 入门基础:开启编程新世界的大门
java·jvm·c++