Java 调用 Groovy 脚本的简单案例

Java 调用 Groovy 脚本的简单案例

前言

Groovy 和 Java 都是使用 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
相关推荐
kimnoic13 小时前
Python数据库学习心得:SQLite、MySQL、PostgreSQL优缺点
开发语言·python
别动我齐刘海13 小时前
C++ 工程化学习
java·linux·前端·c++·学习·机器学习·机器人
必须得开心呀14 小时前
python编写带界面的软件,需要安装哪些插件
开发语言·python
code2cat15 小时前
Java进阶篇之AtomicLongFieldUpdater:把累计额度留在对象字段中
java·cas·并发编程
WeiXin_DZbishe15 小时前
基于springboot城市公交实时运营与调度系统-计算机毕设 附源码【课程设计】66173
java·vue.js·spring boot·后端·python·php·课程设计
泡茶喝茶写代码15 小时前
A股量化数据工程:从 REST 接口到策略信号(第 18 篇):放量缩量异动扫描
java·python·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
wewowilling15 小时前
认识微服务
java·运维·微服务·springcloud
代码什么用16 小时前
Java Web 7-10
java·servlet
沫璃染墨16 小时前
《Qt从零入门系列(十三):QSS样式表详解——从选择器与层叠规则到控件美化实战》
开发语言·css·c++·qt·ui·qt6.3·qss