Groovy小結:java調用Groovy方法並傳遞參數

Groovy小結:java調用Groovy方法並傳遞參數

@(JAVA總結)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腳本。this

2.1.1 測試類Person.java

該類用於測試傳遞Java對象到Groovy腳本中code

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

下面腳本中的兩個方法用於測試方法的無參調用和帶參調用orm

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, helloWithParamip

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 + "\n");
}

/**
 * 測試攜帶參數的方法調用
 */
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 + "\n");
}
相關文章
相關標籤/搜索