groovy 整合脚本引擎

我们都知道Java是一种编译型语言,在JVM运行时从外部动态添加或修改对象、参数变量值、代码执行逻辑等比较繁琐(尽管这可以实现)。而像游戏引擎、业务规则引擎等却恰恰需要这种功能。一般这种情况,都是通过整合脚本引擎来实现的。

Java能够和很多脚本语言整合,包括JavaScript(ES5.1 Nashorn引擎)JythonLuaJ等,但是相比较而言,JavaScript(ES5.1)语法比较混乱,缺失很多重要的语言特性,后两者也几乎不更新了,因此一个较好的选择是整合Groovy脚本。

有关groovy这里不过多叙述,我们直接看一个Java程序整合脚本的例子。

pom.xml

<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy</artifactId>
    <version>2.5.9</version>
</dependency>
<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-jsr223</artifactId>
    <version>2.5.9</version>
</dependency>

Main.java

package com.gacfox.demo;

import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyCodeSource;

import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;

public class Main {

    /**
     * 脚本文件地址URL
     */
    private URL url;
    /**
     * 脚本加载器
     */
    private GroovyClassLoader groovyClassLoader;
    /**
     * 脚本类
     */
    private Class clazz = null;
    /**
     * 脚本类实例
     */
    private IMyScript instance = null;

    public static void main(String[] args) {
        Main main = new Main();
        main.init();
        main.myService();
    }

    public void init() {
        groovyClassLoader = new GroovyClassLoader();
        url = getClass().getClassLoader().getResource("scripts/Script1.groovy");
        if (url == null) {
            throw new RuntimeException("脚本未找到!");
        }
    }

    public void myService() {
        Timer timer = new Timer(false);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {

                    long startTime = System.currentTimeMillis();

                    GroovyCodeSource source = new GroovyCodeSource(url);
                    source.setCachable(true);
                    Class currentClazz = groovyClassLoader.parseClass(source);

                    if (clazz != currentClazz || instance == null) {
                        clazz = currentClazz;
                        instance = (IMyScript) currentClazz.newInstance();
                    }
                    String data = instance.getData();

                    long endTime = System.currentTimeMillis();

                    System.out.println("调用耗时" + (endTime - startTime) + "ms 结果: " + data);

                    Thread.sleep(1000);
                } catch (InterruptedException | IllegalAccessException | InstantiationException e) {
                    e.printStackTrace();
                }
            }
        }, 1000, 1000);
    }
}

IMyScript.java

package com.gacfox.demo;

public interface IMyScript {
    public String getData();
}

Script1.groovy

package scripts

import com.gacfox.demo.IMyScript

class Script1 implements IMyScript {

    String data = "测试"

    @Override
    String getData() {
        return data
    }
}

Main.java就是我们的Java程序,其中有一个调用IMyScript.getData()的循环。但是,这个方法的实现其实并不在Java程序中,而是在groovy脚本中。每次循环时,都会调用脚本引擎进行解析,如果我们修改了Script1.groovy,该修改下次解释执行时也会立即生效。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap