这里主要总结Java中集成Groovy的应用。

Groovy可以与Java完美集成来扩展我们的应用,比如替代Java+jexl实现算式表达式计算或其它功能。在Ofbiz中也集成了Groovy来执行一些查询功能,并且是开始更多的使用Groovy而不是原有的bsh。这里仅仅初步总结我们在Java项目中如何来应用Groovy扩展我们的应用。
1.使用GroovyShell计算表达式
使用Binding对象将变量传入表达式,并通过GroovyShell返回表达式的计算结果。如下例:
public class GroovyShellExample {
    public static void main(String args[]) {
        Binding binding = new Binding();
        binding.setVariable("x", 10);
        binding.setVariable("language", "Groovy");

GroovyShell shell = new GroovyShell(binding);
        Object value = shell.evaluate("println \"Welcome to $language\"; y = x * 2; z = x * 3; return x ");

System.err.println(value +", " + value.equals(10));
        System.err.println(binding.getVariable("y") +", " + binding.getVariable("y").equals(20));
        System.err.println(binding.getVariable("z") +", " + binding.getVariable("z").equals(30));
    }
}
运行结果如下:
Welcome to Groovy
10, true
20, true
30, true

2.使用GroovyScriptEngine脚本引擎加载Groovy脚本
GroovyScriptEngine从指定的位置(文件系统,URL,数据库等等)加载Groovy脚本,并且随着脚本变化可重新加载它们。和GroovyShell一样,GroovyScriptEngine也可以传进变量值返回脚本的计算结果。这样我们可以把一些可用的计算公式或计算条件写入Groovy脚本中来执行应用计算。当这些公式或计算条件变更时,我们可更方便地进行更改计算。如:
public class GroovyScriptEngineExample {
    public static void main(String args[]) {
        try {
            String[] roots = new  String[]{".\\src\\sample\\"} ;//定义Groovy脚本引擎的根路径
            GroovyScriptEngine engine = new GroovyScriptEngine(roots);
            Binding binding = new Binding();
            binding.setVariable("language", "Groovy");
            Object value = engine.run("SimpleScript.groovy", binding);
            assert value.equals("The End");

} catch (Exception e) {
            e.printStackTrace();
        }
    }
}
SimpleScript.groovy脚本如下:
//SimpleScript.groovy
println "Welcome to $language"
return "The End"

运行结果如下:
Welcome to Groovy

3.使用GroovyClassLoader动态地载入Groovy的类
下例现示如何使用GroovyClassLoader加载Groovy类并且调用该类的一个方法
package sample;
public class GroovyClassLoaderExample {
    public static void main(String args[]) {
        try {
            GroovyClassLoader loader = new GroovyClassLoader();
            Class fileCreator = loader.parseClass(new File("GroovySimpleFileCreator.groovy"));
            GroovyObject object = (GroovyObject) fileCreator.newInstance();
            object.invokeMethod("createFile", "C:\\temp\\emptyFile.txt");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
GroovySimpleFileCreator.groovy文件如下:
package sample;
class GroovySimpleFileCreator {
    public createFile(String fileName){
        File file = new File(fileName);
        file.createNewFile();
    }
}
使用GroovyClassLoader另一种情景便是:存在一个Java接口和一个实现该Java接口的Groovy类。此时,可以通过GroovyClassLoader加载Groovy实现类到应用中,这样就可以直接调用该接口的方法。
接口定义如下:
package sample;
public interface IFoo {
    Object run(Object foo);
}
package sample;
public class InvokeGroovy {
    public static void main(String[] args) {
        ClassLoader cl = new InvokeGroovy().getClass().getClassLoader();
        GroovyClassLoader groovyCl = new GroovyClassLoader(cl);
        try {
            //从文件中读取,将实现IFoo接口的groovy类写在一个groovy文件中
            //Class groovyClass = groovyCl.parseClass(new File("./src/sample/Foo.groovy"));
            //直接使用Groovy字符串,也可以获得正确结果
           
Class groovyClass = groovyCl.parseClass("package sample; \r\n class Foo
implements IFoo {public Object run(Object foo) {return
2+2>1}}");//这个返回true
            IFoo foo = (IFoo) groovyClass.newInstance();
            System.out.println(foo.run(new Integer(2)));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.使用JAVA脚本API
Java SE 6 引入了对 Java Specification Request(JSR)223
的支持,JSR 223 旨在定义一个统一的规范,使得 Java 应用程序可以通过一套固定的接口与各种脚本引擎交互,从而达到在 Java
平台上调用各种脚本语言的目的。每一个脚本引擎就是一个脚本解释器,负责运行脚本,获取运行结果。ScriptEngine 接口提供了许多 eval
函数的变体用来运行脚本,这个函数的功能就是获取脚本输入,运行脚本,最后返回输出。
下例显示了一个使用JAVA脚本API运行Groovy的例子:
public class GroovyJSR223Example {
    public static void main(String args[]) {
        try {
            ScriptEngineManager factory = new ScriptEngineManager();
            ScriptEngine engine = factory.getEngineByName("groovy");
            String HelloLanguage = "def hello(language) {return \"Hello $language\"}";
            engine.eval(HelloLanguage);
            Invocable inv = (Invocable) engine;
            Object[] params = {new String("Groovy")};
            Object result = inv.invokeFunction("hello", params);
            assert result.equals("Hello Groovy");
            System.err.println(result);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
Java脚本API除了可以运行Groovy外,还可以运行其它脚本程序,如JavaScript、BSH等。

以下参考<<Java SE 6 新特性: 对脚本语言的支持>> http://www.ibm.com/developerworks/cn/java/j-lo-jse66/
javax.script.ScriptContext 接口和 javax.script.Bindings 接口定义了脚本引擎的上下文
   ? Bindings 接口:Java 应用程序和脚本程序通过这些“键-值”对交换数据。
  
? ScriptContext 接口:ScriptEngine 通过 ScriptContext 实例就能从其内部的 Bindings
中获得需要的属性值。ScriptContext 接口默认包含了两个级别的 Bindings
实例的引用,分别是全局级别和引擎级别.ScriptContext 还允许用户重定向引擎执行时的输入输出流。
public class Redirectory {
    public static void main(String[] args) throws Exception {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("javascript");

PipedReader pr = new PipedReader();
        PipedWriter pw = new PipedWriter(pr);
        PrintWriter writer = new PrintWriter(pw);
        engine.getContext().setWriter(writer);

String script = "println('Hello from JavaScript')";
        engine.eval(script);
       
        BufferedReader br =new BufferedReader(pr);
        System.out.println(br.readLine());
    }
}
共有三个级别的地方可以存取属性,分别是
ScriptEngineManager 中的 Bindings,ScriptEngine 实例对应的 ScriptContext 中含有的
Bindings,以及调用 eval 函数时传入的
Bingdings。离函数调用越近,其作用域越小,优先级越高。下例中可以看出各个属性的存取优先级:
public class ScopeTest {
    public static void main(String[] args) throws Exception {
        String script="println(greeting)";
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("javascript");
       
        //Attribute from ScriptEngineManager
        manager.put("greeting", "Hello from ScriptEngineManager");
        engine.eval(script);

//Attribute from ScriptEngine
        engine.put("greeting", "Hello from ScriptEngine");
        engine.eval(script);

//Attribute from eval method
        ScriptContext context = new SimpleScriptContext();
        context.setAttribute("greeting", "Hello from eval method", ScriptContext.ENGINE_SCOPE);
        engine.eval(script,context);
    }
}

在 Java 脚本 API 中还有两个脚本引擎可以选择是否实现的接口,这个两个接口不是强制要求实现的,即并非所有的脚本引擎都能支持这两个函数:
  
? Invocable 接口:允许 Java 平台调用脚本程序中的函数或方法。Invocable 接口还允许 Java
应用程序从这些函数中直接返回一个接口,通过这个接口实例来调用脚本中的函数或方法,从而我们可以从脚本中动态的生成 Java 应用中需要的接口对象。
   ? Compilable 接口:允许 Java 平台编译脚本程序,供多次调用。
下例调用脚本中的函数:
public class CompilableTest {
    public static void main(String[] args) throws ScriptException, NoSuchMethodException {
        String script = " function greeting(message){println (message);}";
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("javascript");
        engine.eval(script);

if (engine instanceof Invocable) {
            Invocable invocable = (Invocable) engine;
            invocable.invokeFunction("greeting", "hi");
            // It may through NoSuchMethodException
            try {
                invocable.invokeFunction("nogreeing");
            } catch (NoSuchMethodException e) {
                // expected
            }
        }
    }
}
下例演示了如何使用 Compiable 接口来调用脚本:
public class CompilableTest {
    public static void main(String[] args) throws ScriptException {
        String script = " println (greeting); greeting= 'Good Afternoon!' ";
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("javascript");
        engine.put("greeting", "Good Morning!");
       
        if (engine instanceof Compilable) {
            Compilable compilable = (Compilable) engine;
            CompiledScript compiledScript = compilable.compile(script);
            compiledScript.eval();
            compiledScript.eval();
        }
    }
}

Java中运行动态脚本的更多相关文章

  1. JAVA嵌入运行Groovy脚本

    摘自: http://shift-alt-ctrl.iteye.com/blog/1938238 . 最近设计一个数据统计系统,系统中上百种数据统计维度,而且这些数据统计的指标可能随时会调整.如果基于 ...

  2. monkeyrunner之eclipse中运行monkeyrunner脚本之环境搭建(四)

    monkeyrunner脚本使用Python语法编写,但它实际上是通过Jython来解释执行. Jython是Python的Java实现,它将Python代码解释成Java虚拟机上的字节码并执行,这种 ...

  3. java中的动态代理机制

    java中的动态代理机制 在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface).另一个则是 Proxy(Class),这一个类和接口是实现 ...

  4. 十分钟理解Java中的动态代理

    十分钟理解 Java 中的动态代理   一.概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品.关于微商代理,首先我们从他们那里买东西时通常不知道 ...

  5. 转载:monkeyrunner之eclipse中运行monkeyrunner脚本之环境搭建(四)

    转载自:lynnLi 的monkeyrunner之eclipse中运行monkeyrunner脚本之环境搭建(四) monkeyrunner脚本使用Python语法编写,但它实际上是通过Jython来 ...

  6. 深度剖析java中JDK动态代理机制

    https://www.jb51.net/article/110342.htm 本篇文章主要介绍了深度剖析java中JDK动态代理机制 ,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定 ...

  7. 一文读懂Java中的动态代理

    从代理模式说起 回顾前文: 设计模式系列之代理模式(Proxy Pattern) 要读懂动态代理,应从代理模式说起.而实现代理模式,常见有下面两种实现: (1) 代理类关联目标对象,实现目标对象实现的 ...

  8. 『动善时』JMeter基础 — 57、Linux系统中运行JMeter脚本

    目录 1.Linux系统中安装Java环境 (1)解压Java安装包 (2)配置Java环境变量 (3)验证Java环境是否配置成功 2.Linux系统中安装JMeter (1)下载JMeter (2 ...

  9. 使用Java中的动态代理实现数据库连接池

    2002 年 12 月 05 日 作者通过使用JAVA中的动态代理实现数据库连接池,使使用者可以以普通的jdbc连接的使用习惯来使用连接池. 数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的 ...

随机推荐

  1. 助教培训第四次作业——熟练掌握GitHub及Git的使用方法

    助教培训第四次作业——熟练掌握GitHub及Git的使用方法 1.Git 命令的理解和使用 常用的Git命令可以查看官方文档,官方文档的网址:https://git-scm.com/docs .虽然是 ...

  2. 数据结构(python)

    列表 list 在头部进行插入是个相当耗时的操作(需要把后边的元素一个一个挪个位置).假如你需要频繁在数组两头增删,list 就不太合适.数组是最常用到的一种线性结构,其实 python 内置了一个 ...

  3. 【经典/基础BFS+略微复杂的题意】PAT-L3-004. 肿瘤诊断

    L3-004. 肿瘤诊断 在诊断肿瘤疾病时,计算肿瘤体积是很重要的一环.给定病灶扫描切片中标注出的疑似肿瘤区域,请你计算肿瘤的体积. 输入格式: 输入第一行给出4个正整数:M.N.L.T,其中M和N是 ...

  4. Java eclipse等常见问题汇总

    1.Eclipse 注释模板设置 2.eclipse注释字体大小显示不一样大

  5. java中的assert

    Java陷阱之assert关键字   一.概述   在C和C++语言中都有assert关键,表示断言. 在Java中,同样也有assert关键字,表示断言,用法和含义都差不多.   二.语法   在J ...

  6. springcloud注册中心Eureka<英 [juəˈri:kə]>的基本搭建

    1.http://start.spring.io搭建基本的springboot环境,版本用的是1.5.10 2.在pom文件中添加注册中心的jar包和springcloud的jar包 <!-- ...

  7. python - Flask 基础 - 蓝图( Blueprint )(2)

    """ 蓝图:为开发者提供的目录结构 - 使用: 1. 根目录创建一个跟项目名一样的文件 - 创建后第一步,在这个文件夹中添加一个 __init__.py 的配置文件 - ...

  8. Helm:kubernetes应用包管理工具

    概要 Helm:kubernetes应用包管理工具 K8s部署应用的时候,应用会通过yaml描述信息调用K8s-api:Helm即是管理这些Yaml的应用包管理工具 组成 Helm包含5个部分 Hel ...

  9. 51NOD 1452 - 加括号

    DP预处理每个区间的值,再枚举括号位置就好了 #include <bits/stdc++.h> using namespace std; typedef long long ll; con ...

  10. CodeForces 840C - On the Bench | Codeforces Round #429 (Div. 1)

    思路来自FXXL中的某个链接 /* CodeForces 840C - On the Bench [ DP ] | Codeforces Round #429 (Div. 1) 题意: 给出一个数组, ...