Java 集成 groovy 构建规则引擎


#Java 笔记


引入 Groovy 依赖

在 build.gralde 中:

dependencies {
    // https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-all
    compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.5.9'
}

执行 groovy 脚本的几种方法

方法1

import groovy.lang.Binding;
import groovy.lang.GroovyShell;

public class Demo {

    public static void main(String[] args) {
        Binding binding = new Binding();

        // 绑定变量到 groovy 执行环境
        binding.setVariable("foo", new Integer(2));

        // 构建 groovy shell
        GroovyShell shell = new GroovyShell(binding);

        // 执行脚本
        Object value = shell.evaluate("println 'Hello World!'; x = 123; return foo * 10");

        // 执行结果
        System.out.printf("执行结果:%s, 类型: %s\n", value, value.getClass().getCanonicalName());

        // 获取执行过程中的变量
        System.out.printf("执行过程中的x变量:%s, 类型: %s\n", binding.getVariable("x"), binding.getVariable("x").getClass().getCanonicalName());
    }

}

执行结果:

Hello World!
执行结果:20, 类型: java.lang.Integer
执行过程中的x变量:123, 类型: java.lang.Integer

方法2

import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;

public class Demo {

    public static void main(String[] args) {

        // 绑定变量到 groovy 执行环境
        Binding binding = new Binding();
        binding.setVariable("foo", new Integer(2));

        // 构建 groovy script
        GroovyShell shell = new GroovyShell();
        Script script = shell.parse("println 'Hello World!'; x = 123; return foo * 10");
        script.setBinding(binding);  // 绑定

        // 执行脚本
        Object value = script.run();

        // 执行结果
        System.out.printf("执行结果:%s, 类型: %s\n", value, value.getClass().getCanonicalName());

        // 获取执行过程中的变量
        System.out.printf("执行过程中的x变量:%s, 类型: %s\n", binding.getVariable("x"), binding.getVariable("x").getClass().getCanonicalName());
    }

}

执行结果:

Hello World!
执行结果:20, 类型: java.lang.Integer
执行过程中的x变量:123, 类型: java.lang.Integer

方法3

使用 InvokerHelper.createScript 创建脚本对象。

import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import org.codehaus.groovy.runtime.InvokerHelper;

public class Demo {

    public static void main(String[] args) {

        // 绑定变量到 groovy 执行环境
        Binding binding = new Binding();
        binding.setVariable("foo", new Integer(2));

        GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
        Class scriptClass = groovyClassLoader.parseClass("println 'Hello World!'; x = 123; return foo * 10");

        // 执行脚本
        Object value = InvokerHelper.createScript(scriptClass, binding).run();

        // 执行结果
        System.out.printf("执行结果:%s, 类型: %s\n", value, value.getClass().getCanonicalName());

        // 获取执行过程中的变量
        System.out.printf("执行过程中的x变量:%s, 类型: %s\n", binding.getVariable("x"), binding.getVariable("x").getClass().getCanonicalName());
    }

}

方法4

执行 groovy 文件。

todo

示例1:在 groovy 脚本中执行 java 定义的函数

示例:

import groovy.lang.Binding;
import groovy.lang.GroovyShell;

public class Demo {

    public static class Func {

        public long add(long a, long b) {
            return a+b;
        }

    }

    public static void main(String[] args) {
        Binding binding = new Binding();
        binding.setVariable("func", new Func());
        GroovyShell shell = new GroovyShell(binding);
        Object value = shell.evaluate("return func.add(1, 1)");
        System.out.printf("执行结果:%s, 类型:%s\n", value, value.getClass().getCanonicalName());
    }

}

执行结果:

执行结果:2, 类型:java.lang.Long

示例2:在 groovy 脚本中执行 java 定义的静态函数

也可以执行java 中定义的静态方法:

import groovy.lang.Binding;
import groovy.lang.GroovyShell;

public class Demo {

    public static class Func {

        // 这是一个静态方法
        public static long add(long a, long b) {
            return a+b;
        }
    }

    public static void main(String[] args) {
        Binding binding = new Binding();
        binding.setVariable("func", Func.class);
        GroovyShell shell = new GroovyShell(binding);
        Object value = shell.evaluate("return func.add(1, 1)");
        System.out.printf("执行结果:%s, 类型:%s\n", value, value.getClass().getCanonicalName());

    }

}

示例3:传入上下文

Binding 本身也是一种上下文,但有时需要每一个java函数能感知到上下文,此时需要其他的实现方式。

传入上下文的方法有很多,比如作为函数参数,比如作为类的构造函数参数,比如放入 ThreadLocal 。

示例:

import groovy.lang.Binding;
import groovy.lang.Closure;
import groovy.lang.GroovyShell;

import java.util.HashMap;
import java.util.Map;


public class Demo {

    public static class Func {

        private Map<String, Object> context;

        // 上下文作为构造函数参数传入
        public Func(Map<String, Object> context) {
            this.context = context;
        }

        public long add(long a, long b) {
            System.out.println("add 方法上下文: " + context);
            return a+b;
        }
    }

    public static void main(String[] args) {

        // 构造上下文
        Map<String, Object> context = new HashMap<>();
        context.put("name", "lt");

        Binding binding = new Binding();
        binding.setVariable("func", new Func(context));

        GroovyShell shell = new GroovyShell(binding);

        Object value = shell.evaluate("return func.add(1, 1)");

        System.out.printf("执行结果:%s, 类型:%s\n", value, value.getClass().getCanonicalName());
    }
}

执行结果:

add 方法上下文: {name=lt}
执行结果:2, 类型:java.lang.Long

示例4:闭包

groovy 有一个闭包的概念,类似 java 中的 lambda 。

示例:

import groovy.lang.Binding;
import groovy.lang.Closure;
import groovy.lang.GroovyShell;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


public class Demo {

    public static class Func {

        // 过滤函数,第2个参数是闭包
        public List<Integer> filter(List<Integer> list, Closure<Boolean> closure) {
            return list.stream().filter(x -> {
                return closure.call(x);
            }).collect(Collectors.toList());
        }

    }

    public static void main(String[] args) {
        Binding binding = new Binding();
        binding.setVariable("func", new Func());

        GroovyShell shell = new GroovyShell(binding);

        Object value = shell.evaluate("return func.filter([-1,2,3,4], {x -> x > 0} )");

        System.out.printf("执行结果:%s, 类型:%s\n", value, value.getClass().getCanonicalName());
    }
}

执行结果:

执行结果:[2, 3, 4], 类型:java.util.ArrayList

示例5:在 Java 中定义一个 Groovy 闭包类

import groovy.lang.Binding;
import groovy.lang.Closure;
import groovy.lang.GroovyShell;

public class Demo {


    // 这是一个 groovy 闭包
    public static class Add extends Closure<Long> {

        public Add() {
            super(null, null);
        }

        @Override
        public Long call(Object... args) {
            long result = 0;
            for (Object obj : args) {
                if (obj instanceof Integer) {
                    result = result + (Integer) obj;
                    continue;
                }

                if (obj instanceof Long) {
                    result = result + (Long) obj;
                    continue;
                }
            }
            return result;
        }



    }

    public static void main(String[] args) {
        Binding binding = new Binding();

        binding.setVariable("add", new Add());

        GroovyShell shell = new GroovyShell(binding);

        Object value = shell.evaluate("return add(1,2,3)");

        System.out.printf("执行结果:%s, 类型:%s\n", value, value.getClass().getCanonicalName());
    }

}

执行结果:

执行结果:6, 类型:java.lang.Long

示例6:在 groovy 中修改 java 变量

import groovy.lang.Binding;
import groovy.lang.GroovyShell;

import java.util.Arrays;
import java.util.List;


public class Demo {

    public static class Person {
        public String name;
        public int age;
        public List<String> books;

        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", books=" + books +
                    '}';
        }
    }

    public static void main(String[] args) {
        Binding binding = new Binding();

        Person person = new Person();
        person.name = "lt";
        person.age = 10;
        person.books = Arrays.asList("book0", "book1");

        System.out.println("修改前: " + person);

        binding.setVariable("person", person);

        GroovyShell shell = new GroovyShell(binding);

        Object value = shell.evaluate("println 'in groovy books : ' + person.books; person.books[1] = 'new book1';return person.name");

        System.out.printf("执行结果:%s, 类型:%s\n", value, value.getClass().getCanonicalName());

        System.out.println("修改后: " + person);
    }
}

执行结果:

修改前: Person{name='lt', age=10, books=[book0, book1]}
in groovy books : [book0, book1]
执行结果:lt, 类型:java.lang.String
修改后: Person{name='lt', age=10, books=[book0, new book1]}

参考

  • http://ifeve.com/embedding-groovy/


( 本文完 )