• Groovy小结:java调用Groovy方法并传递参数


    @(JAVA总结)

    1. 场景描述

    在网上查了资料发现,java有三种方式调用groovy脚本。但是真正在实际的服务器环境中,嵌入groovy脚本往往需要满足下面的条件:

    1. 可以直接调用groovy脚本中的方法
    2. 能传递对象到groovy方法中,不仅仅是字符串
    3. 提供脚本缓存机制,不用每次调用脚本的时候,都到磁盘读取
    4. 修改groovy后能实时生效

    只有满足了上面的这些要求,才能安心的将其嵌入到现有的Java后台服务中。
    下面就来具体探讨下具体实现的步骤。

    2. 解决方案

    其实,GroovyScriptEngine类就已经提供了上面所说的功能。
    主要使用GroovyScriptEngine.loadScriptByName来读取脚本,loadScriptByName方法内部提供了缓存功能,在读取groovy脚本的时候,会优先从缓存中读取,如果缓存中没有的话,才去读取脚本,如下:
    Alt text

    2.1 相关测试类和脚本

    在后面的测试后,会用到下面的java类和groovy脚本。

    2.1.1 测试类Person.java

    该类用于测试传递Java对象到Groovy脚本中

    public class Person {
        public String name;
        public String address;
        public Integer age;
        
        public Person(String name, String addr, Integer age){
            this.name = name;
            this.address = addr;
            this.age = age;
        }
        
        public String toString(){
            return String.format("[Person: name:%s, address:%s, age:%s]", name,address, age);
        }
    }

    2.1.2 测试脚本hello2.groovy

    下面脚本中的两个方法用于测试方法的无参调用和带参调用

    def helloWithoutParam(){
        println "start to call helloWithoutParam!"
        return "success, helloWithoutParam";
    }
    
    def helloWithParam(person, id){
        println "start to call helloWithParam, param{person:" + person + ", id:" + id + "}";
        return "success, helloWithParam";
    }

    2.2 java调用Groovy脚本方法(无参)

    public static void testGroovy2(){
        try {  
            Class scriptClass = groovyScriptEngine.loadScriptByName("hello2.groovy");
            GroovyObject scriptInstance = (GroovyObject)scriptClass.newInstance();
            Object ret = scriptInstance.invokeMethod("helloWithoutParam", null);
            System.out.println("testGroovy2:" + ret);
        } catch (Exception e) {  
            e.printStackTrace();  
            System.out.println("Exception e="+e.toString());  
        } 
    }

    执行结果:
    start to call helloWithoutParam!
    testGroovy2: success, helloWithoutParam

    2.3 java调用Groovy脚本方法(带参)

    @SuppressWarnings({ "rawtypes" })
    public static void testGroovy3(){
        try {  
            Person person = new Person("wchi", "nanjing", 30);
            Class scriptClass = groovyScriptEngine.loadScriptByName("hello2.groovy");
            GroovyObject scriptInstance = (GroovyObject)scriptClass.newInstance();
            Object ret = scriptInstance.invokeMethod("helloWithParam", new Object[]{person,"lxi"}); 
            System.out.println("testGroovy3:" + ret);
        } catch (Exception e) {  
            e.printStackTrace();  
            System.out.println("Exception e="+e.toString());  
        } 
    }

    返回结果:
    start to call helloWithParam, param{person:[Person: name:wchi, address:nanjing, age:30], id:lxi}
    testGroovy3: success, helloWithParam

    2.4 封装的公用类

    可以将上面的代码封装成公用类,这样就方便很多,如下:

    public class GroovyCommonUtil {
        private static final Logger log = LoggerFactory.getLogger(GroovyCommonUtil.class);
        //该变量用于指明groovy脚本所在的父目录
        static String root[]=new String[]{"bin/groovy/"};  
        static GroovyScriptEngine groovyScriptEngine;  
        
        static{
            try {
                groovyScriptEngine=new GroovyScriptEngine(root);
            } catch (IOException e) {
                e.printStackTrace();
            }  
        }
        
        /**
         *  用于调用指定Groovy脚本中的指定方法 
         * @param scriptName    脚本名称
         * @param methodName    方法名称
         * @param params        方法参数
         * @return
         */
    @SuppressWarnings({ "rawtypes"})
    public Object invokeMethod(String scriptName, String methodName, Object... params) throws Exception{
        Object ret = null;
        Class scriptClass = null;
        GroovyObject scriptInstance = null;
        
        try {
            scriptClass = groovyScriptEngine.loadScriptByName(scriptName);
            scriptInstance = (GroovyObject)scriptClass.newInstance();
        } catch (ResourceException | ScriptException | InstantiationException | IllegalAccessException e1) {
            log.warn("加载脚本["+scriptName+"]出现异常", e1);
            throw new Exception("加载脚本"+scriptName+"失败");
        }
    
        try {
            ret = (String)scriptInstance.invokeMethod(methodName, params);
        } catch (IllegalArgumentException e) {
            log.warn("执行方法" + methodName + "参数出现异常, 参数为" + params, e);
            throw new Exception("调用方法[" + methodName + "]失败,因参数不合法");
        } catch(Exception e){
            log.warn("执行方法" + methodName + "出现异常", e);
            throw new Exception("调用方法[" + methodName + "]失败");
        }
    
        return ret;
    }

    使用上面的公用类,改写的测试代码如下:

    /**
     * 测试没有参数的方法调用
     */
    public static void testGroovyWithoutParam(){
        String result = (String)GroovyCommonUtil.invokeMethod("hello2.groovy", "helloWithoutParam");
        System.out.println("testGroovy4: " + result + "
    ");
    }
    
    /**
     * 测试携带参数的方法调用
     */
    public static void testGroovyWithParam(){
        Person person = new Person("wchi", "nanjing", 30);
        String result = (String)GroovyCommonUtil.invokeMethod("hello2.groovy", "helloWithParam", person, "testGroovy4");
        System.out.println("testGroovy4: " + result + "
    ");
    }
  • 相关阅读:
    java.lang.IllegalStateException: Failed to load property source from location 'classpath:/application.yml'
    generate failed: Cannot resolve classpath entry: mysql-connector-java-5.1.38.jar
    Spring boot 零配置开发微服务
    【ABAP系列】SAP ABAP BAPI_REQUISITION_CREATE创建采购申请
    【ABAP系列】SAP ABAP 字符编码与解码、Unicode
    【ABAP系列】ABAP CL_ABAP_CONV_IN_CE
    【Fiori系列】浅谈SAP Fiori的设计美感与发展历程
    【Fiori系列】为什么SAP Fiori活的如此精致
    【ABAP系列】SAP ABAP下载带密码的Excel文件
    【ABAP系列】SAP ABAP 高级业务应用程序编程(ABAP)
  • 原文地址:https://www.cnblogs.com/zhanying999666/p/10156179.html
Copyright © 2020-2023  润新知