1.什么是groovy?
Groovy 是构建在 JVM 上的一个轻量级却强大的动态语言,它结合了 Python、Ruby 和 Smalltalk 的许多强大的特性。 Groovy 就是用 Java 写的,Groovy 语法与 Java 语法类似,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码。相对于 Java,它在编写代码的灵活性上有非常明显的提升,Groovy 可以使用其他 Java 语言编写的库。 Groovy 是增强 Java 平台的唯一的脚本语言。它提供了类似于 Java 的语法,内置映射(Map)、列表(List)、方法、类、闭包(closure)以及生成器。脚本语言不会替代系统编程语言,两者是相互补充的。
系统编程语言的目的:
- 开发复杂的算法或者数据结构
- 实现计算密集型应用
- 操作大型数据集
- 实现定义良好的、变更缓慢的需求
脚本语言应用的目的:
- 连接已有的组件
- 处理经常变化的多种类型的实体
- 具有图形化用户界面
- 拥有快速变化的功能
集成groovy的好处:
- groovy跟java都是基于jvm的语言,可以在java项目中集成groovy并充分利用groovy的动态功能;
- groovy兼容几乎所有的java语法,开发者完全可以将groovy当做java来开发,甚至可以不使用groovy的特有语法,仅仅通过引入groovy并使用它的动态能力;
- groovy可以直接调用项目中现有的java类(通过import导入),通过构造函数构造对象并直接调用其方法并返回结果;
- groovy支持通过GroovyShell预设对象,在groovy动态脚本中直接调用预设对象的方法。因此我们可以通过将spring的bean预设到GroovyShell运行环境中,在groovy动态脚本中直接调用spring容器中bean来调用其方法,这点对于spring项目非常方便!
2.代码工程
实验目的
如何通过动态groovy脚本直接调用spring context中注册的bean的方法
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springboot-demo</artifactId><groupId>com.et</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>groovy</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-all --><dependency><groupId>org.codehaus.groovy</groupId><artifactId>groovy-all</artifactId><version>2.4.7</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.10</version></dependency></dependencies>
</project>
conotroller
将binding对象注入后,在初始化方法init()中用binding对象构造GroovyShell对象,在提供的execute接口实现中用GroovyShell对象生成Script脚本对象,并调用Script的run()方法运行动态脚本并返回结果。
package com.et.groovy.controller;import com.et.groovy.component.TestScript;
import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.PostConstruct;@RestController
@RequestMapping("/groovy/script")
public class GroovyScriptController {@Autowiredprivate Binding groovyBinding;private GroovyShell groovyShell;@PostConstructpublic void init(){GroovyClassLoader groovyClassLoader = new GroovyClassLoader(this.getClass().getClassLoader());CompilerConfiguration compilerConfiguration = new CompilerConfiguration();compilerConfiguration.setSourceEncoding("utf-8");compilerConfiguration.setScriptBaseClass(TestScript.class.getName());groovyShell = new GroovyShell(groovyClassLoader, groovyBinding, compilerConfiguration);}@RequestMapping(value = "/execute", method = RequestMethod.POST)public String execute(@RequestBody String scriptContent) {Script script = groovyShell.parse(scriptContent); return String.valueOf(script.run());}
}
service
package com.et.groovy.service;import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import org.springframework.stereotype.Service;@Service
public class TestService {public String testQuery(long id){return "Test query success, id is " + id;}public static void main(String[] args) {Binding groovyBinding = new Binding();groovyBinding.setVariable("testService", new TestService());GroovyShell groovyShell = new GroovyShell(groovyBinding);String scriptContent = "import pers.doublebin.example.groovy.script.service.TestService\n" +"def query = new TestService().testQuery(1L);\n" +"query";/*String scriptContent = "def query = testService.testQuery(2L);\n" +"query";*/Script script = groovyShell.parse(scriptContent);System.out.println(script.run());}
}
config
首先配置类可以实现org.springframework.context.ApplicationContextAware接口用来获取应用上下文,然后再配置类中通过应用上下文获取所有的bean并注册到groovy的Binding中
package com.et.groovy.config;import groovy.lang.Binding;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.Map;@Configuration
public class GroovyBindingConfig implements ApplicationContextAware {private ApplicationContext applicationContext;//@Bean("groovyBinding")public Binding groovyBinding() {Binding groovyBinding = new Binding();Map<String, Object> beanMap = applicationContext.getBeansOfType(Object.class);for (String beanName : beanMap.keySet()) {groovyBinding.setVariable(beanName, beanMap.get(beanName));}return groovyBinding;}@Bean("groovyBinding1")public Binding groovyBinding1() {Map<String, Object> beanMap = applicationContext.getBeansOfType(Object.class);return new Binding(beanMap); }@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}
components
groovy支持通过GroovyShell预设对象,在groovy动态脚本中直接调用预设对象的方法
package com.et.groovy.component;import groovy.lang.Script;public class TestScript extends Script {@Overridepublic Object run() {return null;}public Integer add (Integer first, Integer second) {return first + second;}
}
以上只是一些关键代码,所有代码请参见下面代码仓库
代码仓库
- GitHub - Harries/springboot-demo: a simple springboot demo with some components for example: redis,solr,rockmq and so on.
3.测试
启动Spring Boot应用
测试执行groovy脚本
4.引用
- GitHub - double-bin/groovy-script-example: Show how to execute dynamic groovy script in springboot controller.