Java动态调用groovy脚本代码教程

2023-12-18 19:07:58

goovy简介

Goovy是一种基于Java虚拟机(JVM)的动态编程语言,它结合了Python、Ruby和Smalltalk的许多强大特性,并能够与Java完美结合,使用Java所有的库。以下是关于Goovy的详细解释:

语法

Goovy的语法非常简洁明了,类似于Python和Ruby。它支持动态类型和静态类型,可以在运行时进行类型检查和推断。Goovy还支持闭包、高阶函数和匿名函数等特性,这些特性使得代码更加简洁、易于阅读和维护。

类型系统

Goovy的类型系统非常灵活,支持动态类型和静态类型。在动态类型的情况下,变量的类型会在运行时自动推断。在静态类型的情况下,变量的类型需要在编译时声明。Goovy还支持类型转换和类型检查,使得代码更加健壮和可读。

闭包

Goovy支持闭包,闭包可以捕获其创建时所在的词法作用域中的变量。闭包可以作为参数传递给函数,也可以作为函数的返回值。闭包使得代码更加简洁、灵活和可重用。

高阶函数

Goovy支持高阶函数,高阶函数是指接受其他函数作为参数或返回函数的函数。高阶函数使得代码更加简洁、易于阅读和维护。

反射

Goovy支持反射,反射是指在运行时检查程序的行为和结构的能力。通过反射,可以在运行时获取类的信息、创建对象、调用方法等。反射使得代码更加灵活和可扩展。

并发编程

Goovy支持并发编程,它提供了类似于Java的线程和锁等机制,同时也提供了类似于Python的协程和异步编程等机制。这些机制使得开发人员可以更加轻松地编写并发程序,提高程序的性能和可靠性。

集成Java库

Goovy可以无缝集成Java库,开发人员可以使用Java所有的库来编写Goovy代码。这使得开发人员可以更加方便地利用现有的Java资源,同时也使得Goovy成为了一种非常灵活的动态脚本语言。

应用场景

Goovy适用于各种应用场景,例如Web开发、桌面应用、移动应用、游戏开发等。它既可以作为主要开发语言使用,也可以作为辅助语言使用,与Java完美结合,提高开发效率和代码质量。

总之,Goovy是一种非常强大的动态编程语言,它结合了Python、Ruby和Smalltalk的许多强大特性,并能够与Java完美结合,使用Java所有的库。Goovy的语法简洁明了、类型灵活、支持闭包和高阶函数等特性,使得代码更加简洁、易于阅读和维护。同时,Goovy还支持反射和并发编程等机制,使得程序更加灵活和可扩展。Goovy可以无缝集成Java库,使得开发人员可以更加方便地利用现有的Java资源。总之,Goovy是一种非常优秀的编程语言,适用于各种应用场景,值得广大开发人员学习和使用。

引入pom依赖

在maven项目中pom.xml添加如下依赖

        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.4.11</version>
        </dependency>

代码实现

创建一个名为ScriptProvider的groovy脚本辅助类,实现java调用groovy脚本中的方法。完整代码如下:


import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import lombok.extern.slf4j.Slf4j;
import org.springblade.coalface.modules.opcua.dto.OpcData;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * @author tarzan
 */
@Component
@Slf4j
public class ScriptProvider {

    private GroovyObject groovyObject;

    @Value("${app.work-face}")
    private  void loadScript(String name){
        try (GroovyClassLoader classLoader = new GroovyClassLoader()) {
            Class<?> groovyClass = classLoader.parseClass(new File("etc/"+name+".groovy"));
            groovyObject= (GroovyObject) groovyClass.newInstance();
        } catch (InstantiationException | IOException | IllegalAccessException e) {
            log.error(e.getMessage());
        }
    }

    public  void overloadScript(String filePath){
        try (GroovyClassLoader classLoader = new GroovyClassLoader()) {
            Class<?> groovyClass = classLoader.parseClass(new File(filePath));
            groovyObject= (GroovyObject) groovyClass.newInstance();
        } catch (InstantiationException | IOException | IllegalAccessException e) {
            log.error(e.getMessage());
        }
    }

    public float calStentHeight(int i, List<OpcData> dataValues){
        Object[] objects = new Object[]{i,dataValues};
        Object result=groovyObject.invokeMethod("calStentHeight",objects);
        return Float.parseFloat(result.toString());
    }

    public float revisedStentHeight(int i, float value){
        Object[] objects = new Object[]{i,value};
        Object result=groovyObject.invokeMethod("revisedStentHeight",objects);
        return Float.parseFloat(result.toString());
    }

    public float revisedStentStroke(float value) {
        Object[] objects = new Object[]{value};
        Object result=groovyObject.invokeMethod("revisedStentStroke",objects);
        return Float.parseFloat(result.toString());
    }

}

  • app.work-face 是在spring配置文件中的goovy脚本名称
  • etc/“+name+”.groovy 是指在项目根目录下 etc文件夹下 的某个 goovy脚本

groovy脚本代码示例

import org.springblade.coalface.modules.opcua.dto.OpcData

def calStentHeight(int i,List<OpcData> dataValues){
     float d= dataValues.get(i).getValue()
     def f1=0.175
     def f2=0.136
     def e= new BigDecimal(Float.toString(d)).add(f1).add(f2)
    return e.doubleValue()
}

def revisedStentHeight(int i,float height){
    int stentNo=i+1
    if(stentNo<=2||stentNo>=92){
        height=height>3.3||height<1.15?3.3:height
    }else{
        if(height>1.9){
            height=1.9
        }
        if(height<1.15){
            height=1.2
        }
    }
    return height
}

def revisedStentStroke(float stroke){
    if(stroke>900F){
        stroke=900F
    }
    if(stroke<=0F){
        stroke=0F
    }
    return stroke
}

  • groovy 脚本中可以直接引入java的类,使用java对象的方法和属性

调用代码示例

  @Resource
  private ScriptProvider scriptProvider;

 
  private void test() {
      float revised = scriptProvider.revisedStentStroke(modification);    
  }

  • 注入ScriptProvider工具类
  • 通过ScriptProvider工具类调用对应grovvy脚本中的方法

动态监听脚本

当脚本被修改时候,java代码重新加载groovy脚本中的最新代码,需要一个监听工具类FileSystemWatcher,完整代码如下:

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.file.*;

/**
 * @author tarzan
 */
@Component
@AllArgsConstructor
@Slf4j
public class FileSystemWatcher {

    private final ScriptProvider scriptProvider;

    @Async
    public void modifyWatch(){
        try {
            watch(StandardWatchEventKinds.ENTRY_MODIFY);
        } catch (IOException | InterruptedException e) {
            log.error(e.getMessage());
        }
    }

    @SuppressWarnings({"unchecked", "BusyWait"})
    private  void watch(WatchEvent.Kind<Path> eventKind) throws IOException, InterruptedException {
        // 定义你想要监听的路径
        Path path = Paths.get("etc");
        // 创建 WatchService
        WatchService watchService = FileSystems.getDefault().newWatchService();
        // 将路径注册到 WatchService,并指定你想要监听的事件类型
        path.register(watchService, eventKind);

        while (true) {
            // 获取下一个文件系统事件
            WatchKey key = watchService.take();
            for (WatchEvent<?> event : key.pollEvents()) {
                // 获取事件类型
                WatchEvent.Kind<?> kind = event.kind();
                if (kind == StandardWatchEventKinds.OVERFLOW) {
                    continue;
                }
                // 获取发生事件的文件
                WatchEvent<Path> ev = (WatchEvent<Path>) event;
                Path fileName = ev.context();
                // 打印出发生事件的文件名和事件类型
                boolean eventFlag=!fileName.toFile().getName().endsWith("~");
                if(eventFlag){
                    log.info("etc/"+fileName +" be modified");
                    scriptProvider.overloadScript("etc/"+fileName);
                }
            }
            // 重置 WatchKey,以便接收下一个事件
            boolean valid = key.reset();
            if (!valid) {
                break;
            }
            //睡眠1秒
            Thread.sleep(1000);
        }
    }

}
  • @SuppressWarnings 用于抑制编译器产生某些警告,@SuppressWarnings({“unchecked”, “BusyWait”})告诉编译器不要对未检查的类型转换和忙等待产生警告。
  • 这个监听工具类,需要在项目启动的时候调用它的监听方法。下面是代码示例:

创建一个启动监听类 AppStartedListener ,当项目启动完成后,就会调用,groovy脚本文件修改事件,当groovy脚本内的代码被修改后,保存groovy脚本时,会触发更新ScriptProvider类中加载的groovy脚本代码,实现动态更新。


import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springblade.coalface.script.FileSystemWatcher;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;


/**
 *
 * @author tarzan
 * @date 2023-10-05
 */
@Slf4j
@Component
public class AppStartedListener implements ApplicationListener<ApplicationStartedEvent> {

    @Resource
    private FileSystemWatcher fileSystemWatcher;

    @SneakyThrows
    @Override
    public void onApplicationEvent(@NonNull ApplicationStartedEvent event) {
        fileSystemWatcher.modifyWatch();
        log.info("服务初始化。。。");
    }

}

文章来源:https://blog.csdn.net/weixin_40986713/article/details/135067938
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。