最近手上有一个专项要做,专项思路大概就是开发一个服务将所有其他Java开发的自动化工具脚本收口,统一通过这个服务做调度转发。
为什么要聊groovy呢?
大家也都知道,阿里、美团、滴滴、京东等大厂项目基本上都是Java栈为主,其实Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python和Ruby许多强大的特性,Groovy代码能够与Java代码很好地结合,也能用于扩展现有代码,学会Java调用groovy有利于更好的实现自动化。
Groovy有哪些特点呢?
为Java开发者提供了 现代最流行的编程语言特性,而且学习成本很低(几乎为零)。
Groovy拥有处理原生类型,面向对象以及一个Ant DSL,使得创建Shell Scripts变得非常简单。
groovy基本类型也是对象,可以直接调用对象的方法。
支持函数式编程,不需要main函数。
直接编译成Java字节码,这样可以在任何使用Java的地方 使用Groovy。
OK,接下来切入正题,介绍一下怎么通过Java调用Groovy脚本。
Java调用Groovy的几种方法
工具:IntelliJ IDEA
项目:maven项目
依赖:groovy-all包
org.codehaus.groovy groovy-all 3.0.7 pom
一、GroovyShell执行groovy脚本
通过evaluate方法执行groovy脚本
GroovyShell的evaluate方法非常类似于Js的eva方法,可执行一段字符串。
package com.robot.universalrobot.groovyTest;import groovy.lang.GroovyShell;import java.util.logging.Logger;import org.codehaus.groovy.control.CompilationFailedException;import java.io.IOException;/** * @Date 2021/1/1 7:33 下午 **/public class Test_002 { public static void testGroovy2() throws CompilationFailedException, IOException { GroovyShell groovyShell = new GroovyShell(); groovyShell.evaluate("println 'hello Groovy shell.'"); } public static void main(String[] args) { try { testGroovy2(); } catch (IOException error){ error.getStackTrace(); } }}
运行结果
通过evaluate方法调用groovy脚本文件
需要建一个groovy文件,定义要执行的脚本,例如定义一个无参的方法sayHello并调用该方法。
def sayHello() { println 'Hello World.'}sayHello()
在Java中就可以直接调用这个groovy文件执行了,方法如下:
package com.robot.universalrobot.groovyTest;import groovy.lang.GroovyShell;import lombok.Data;import org.codehaus.groovy.control.CompilationFailedException;import java.io.File;import java.io.IOException;import java.util.logging.Logger;/** * @Date 2021/1/1 7:26 下午 **/@Datapublic class test_001 { public static void testGroovy1() throws CompilationFailedException, IOException { GroovyShell groovyShell = new GroovyShell(); Object result = groovyShell.evaluate(new File("src/main/java/com/robot/universalrobot/groovyTest/demo_001.groovy")); } public static void main(String[] args) { try { testGroovy1(); } catch (Exception error){ error.getStackTrace(); } }}
执行结果
给groovy文件传参数并执行
package com.robot.universalrobot.groovyTestdef sayHello(name) { println 'Hello World.' + name}sayHello(name)
Java调用groovy方法
public class test_001 { public static void testGroovy1() throws CompilationFailedException, IOException { // 调用带参数的groovy shell时,使用bind绑定数据 Binding binding = new Binding(); binding.setProperty("name", "软件质量保障"); GroovyShell groovyShell = new GroovyShell(binding); Object result = groovyShell.evaluate(new File("src/main/java/com/robot/universalrobot/groovyTest/demo_001.groovy")); } public static void main(String[] args) { try { testGroovy1(); } catch (Exception error){ error.getStackTrace(); } }}
执行结果
二、GroovyClassLoader动态加载Groovy Class
你也许熟悉Java的ClassLoader类加载器,当运行Java程序时,首先运行JVM(Java虚拟机),然后再把Java class加载到JVM运行,负责加载Java class的这部分就叫做Class Loader。而GroovyClassLoader,顾名思义,就是用来加载Groovy类的加载器。
新建groovy class
class demo_002 { String sayHello(String name, String sex, int age) { return "name: " + name + ", sex: " + sex + ", age: " + age; }}
编写Java调用文件
import groovy.lang.GroovyClassLoader;import groovy.lang.GroovyObject;import org.codehaus.groovy.control.CompilerConfiguration;import java.io.File;/** * @Date 2021/1/1 7:58 下午 **/public class Test_003 { private static GroovyClassLoader groovyClassLoader = null; public static void initGroovyClassLoader() { CompilerConfiguration config = new CompilerConfiguration(); config.setSourceEncoding("UTF-8"); // 设置该GroovyClassLoader的父ClassLoader为当前线程的加载器(默认) groovyClassLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader(), config); } /** * 通过GroovyClassLoader加载GroovyShell_2,并反射调用其sayHello(String name, String sex, int age)方法 * */ public static String invokeSayHello(String name, String sex, int age) { String result = ""; File groovyFile = new File("src/main/java/com/robot/universalrobot/groovyTest/demo_002.groovy"); if (!groovyFile.exists()) { return result; } try { // 获得GroovyShell_2加载后的class Class> groovyClass = groovyClassLoader.parseClass(groovyFile); // 获得GroovyShell_2的实例 GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance(); // 反射调用sayHello方法得到返回值 Object methodResult = groovyObject.invokeMethod("sayHello", new Object[] {name, sex, age}); if (methodResult != null) { result = methodResult.toString(); } } catch (Exception e) { e.getStackTrace(); } return result; } public static void main(String[] args) throws Exception { initGroovyClassLoader(); System.out.println(invokeSayHello("张三", "男", 25)); }}
执行结果
其方式和Java中类的加载反射类似,需要注意的是GroovyClassLoader与Java中的加载器一样,同一个类名的类只能加载一次,如果想再次加载,必须调用GroovyClassLoader的clearCache()方法移除所有已经加载的Groovy Class。
三、GroovyScriptEngine脚本引擎加载Groovy脚本
GroovyScriptEngine从指定的位置(文件系统,URL,数据库等等)加载Groovy脚本,并且随着脚本变化可重新加载它们。GroovyScriptEngine也可以传进变量值返回脚本的计算结果。
以上面栗子中的groovy文件为例。
编写使用GroovyScriptEngine从com.juxinli.groovy.shell包中加载、运行这些script
package com.robot.universalrobot.groovyTest;import groovy.util.GroovyScriptEngine;import groovy.lang.Binding;/** * @Date 2021/1/1 8:07 下午 **/public class test_004 { public static void main(String[] args) throws Exception { // GroovyScriptEngine的根路径,如果参数是字符串数组,说明有多个根路径 GroovyScriptEngine engine = new GroovyScriptEngine("src/main/java/com/robot/universalrobot/groovyTest"); Binding binding = new Binding(); binding.setVariable("name", "软件质量保障"); Object result1 = engine.run("demo_001.groovy", binding); Object result2 = engine.run("demo_003.groovy", binding); }}
执行结果
好啦,以上就是总结的几种执行groovy脚本的方法,欢迎转载分享。
参考文档
https://tool.oschina.net/apidocs/apidoc?api=groovy