
参考资料:
核心定位:Groovy 是 Apache 基金会开源的、基于 JVM 的动态脚本语言,是 Java 的完美超集——所有 Java 代码可直接在 Groovy 中运行,无需修改。
Groovy 凭借简洁的语法、强大的动态特性,能快速实现 Java 项目的动态脚本扩展(如动态规则配置、脚本化计算等),且与 Java 兼容性极佳,是 Java 项目实现“灵活扩展”的优选方案。
一、Groovy 与 Java21 的核心关联
1. 版本兼容
- Groovy 4.0.15+ 版本完全兼容 Java(推荐最新稳定版 4.0.22),支持 Java 的虚拟线程、模式匹配等新特性。
- 旧版本(Groovy 3.x 及以下)不支持 Java,会出现编译报错、运行异常,务必选择 4.0.15+ 版本。
- Groovy 本质是 JVM 语言,编译后生成 class 文件,与 Java 字节码完全兼容,可与 Java 类双向互调、无缝集成。
2. 集成核心价值
- ✅ 动态扩展:无需重启 Java 服务,即可修改脚本实现业务规则调整(如动态计算、权限校验)。
- ✅ 语法简洁:Groovy 简化了 Java 的繁琐语法(省略分号、get/set 方法、main 方法等),提升开发效率。
- ✅ 无缝兼容:Java 的类、接口、第三方依赖(如 Spring Boot、MyBatis)可直接在 Groovy 中使用,反之亦然。
- ✅ 脚本化能力:支持字符串形式的脚本动态执行,适合实现可配置的业务逻辑(如动态规则引擎)。
二、Java 项目集成 Groovy
本章节聚焦“集成实操”,覆盖 IDEA 配置、Maven 依赖引入、集成测试,确保你能快速将 Groovy 集成到已有的 Java 项目中,或新建集成项目。
1. IDEA 环境配置
前提:如基于 JDK21,确保已安装 Java JDK,并配置好环境变量(java -version 可正常显示 21 版本)。
- 打开 IDEA → File → Settings → Plugins → 搜索
Groovy(Apache 官方插件,IDEA 自带,无需额外下载),启用后重启 IDEA。
- 新建 Java 项目(或打开已有 Java 项目):
- 新建项目:选择 Java → 配置 JDK 为 Java → 完成。
- 已有项目:确认 Project Structure → Project SDK 为 Java。
- 为项目添加 Groovy 支持:
- 右键项目 → Add Framework Support → 勾选
Groovy → 选择 Groovy SDK(若未检测到,点击 Download 下载 4.0.22 版本,自动适配 Java)。
- 配置完成后,可新建
.groovy 文件,IDE 会自动识别并提供语法提示。
2. Maven 依赖集成
生产环境必备,核心步骤
在 Java 项目的 pom.xml 中引入 Groovy 核心依赖,无需额外配置,即可实现 Groovy 与 Java 的无缝集成,支持 Groovy 脚本编译、运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| <properties> <java.version>21</java.version> <groovy.version>4.0.22</groovy.version> </properties>
<dependencies> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>${groovy.version}</version> <type>pom</type> </dependency>
<dependency> <groupId>org.craftercms</groupId> <artifactId>groovy-sandbox</artifactId> <version>4.0.0</version> </dependency> </dependencies>
<build> <plugins> <plugin> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-maven-plugin</artifactId> <version>${groovy.version}</version> <executions> <execution> <goals> <goal>compile</goal> <goal>testCompile</goal> </goals> <configuration> <source>21</source> <target>21</target> </configuration> </execution> </executions> </plugin>
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <source>21</source> <target>21</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build>
|
依赖说明:
groovy-all:Groovy 核心依赖,包含所有 Groovy 语法、动态特性、工具类,无需额外引入其他 Groovy 相关依赖。
groovy-maven-plugin:Apache 官方提供的 Groovy 编译插件,确保 Groovy 代码能与 Java 代码一起编译,生成可运行的 class 文件。
groovy-sandbox:可选依赖,用于生产环境安全防护,限制 Groovy 脚本的执行权限,防止恶意脚本调用危险 API(如文件操作、网络请求)。
3. 集成测试:双向互调
集成完成后,通过 2 个简单案例,验证 Java 能调用 Groovy 脚本/类,Groovy 能调用 Java 类,确保集成无问题。
案例 1:Java 调用 Groovy 脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import groovy.lang.GroovyShell; import java.util.HashMap; import java.util.Map;
public class JavaCallGroovyDemo { public static void main(String[] args) { GroovyShell groovyShell = new GroovyShell();
Object simpleResult = groovyShell.evaluate("1 + 2 * 3"); System.out.println("简单脚本执行结果:" + simpleResult);
Map<String, Object> params = new HashMap<>(); params.put("a", 10); params.put("b", 20); params.forEach(groovyShell::setVariable); Object paramResult = groovyShell.evaluate("a + b"); System.out.println("带参数脚本执行结果:" + paramResult);
String complexScript = """ def list = [1, 2, 3, 4, 5] // 过滤偶数并求和(Groovy 简洁语法) return list.findAll { it % 2 == 0 }.sum() """; Object complexResult = groovyShell.evaluate(complexScript); System.out.println("复杂脚本执行结果:" + complexResult); } }
|
案例 2:Groovy 调用 Java 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
public class JavaUser { private String name; private Integer age;
public JavaUser(String name, Integer age) { this.name = name; this.age = age; }
public String getUserName() { return "Java 用户:" + name; }
public static String getStaticInfo() { return "这是 Java 静态方法,Groovy 可直接调用"; }
public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
def javaUser = new JavaUser("张三", 25)
println javaUser.getUserName()
println "用户姓名:${javaUser.name},年龄:${javaUser.age}"
println JavaUser.getStaticInfo()
javaUser.setAge(26) println "修改后年龄:${javaUser.age}"
|
运行说明:将上述两个文件放入 Java 项目中,直接运行 Java 类或 Groovy 脚本,能正常输出结果,即说明 Groovy 与 Java 集成成功。
三、Groovy 核心语法
作为 Java 开发者,无需从头学习 Groovy,重点掌握其简化语法和核心特性即可,所有 Java 语法在 Groovy 中完全适用。
1. 变量定义:def 关键字
动态类型,简化开发
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def name = "张三" def age = 25 def salary = 12000.5 def isMale = true
String address = "北京市" int phone = 13800138000
def array1 = [1, 2, 3] int[] array2 = [4, 5, 6] as int[] def array3 = new int[]{7, 8, 9}
|
2. 字符串:3种写法 + 插值
Groovy 核心简化特性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| def s1 = '普通字符串'
def name = "李四" def s2 = "我的名字是 ${name},今年 ${2026 - 1998} 岁"
def sql = """ SELECT id, name, age FROM user WHERE id = ${userId} ORDER BY create_time DESC """
def str = " Groovy " println str.trim() println str.toUpperCase() println str.contains("Groovy")
|
3. 空安全:彻底解决 Java 的 NPE 问题
1 2 3 4 5 6 7 8 9 10 11 12 13
| String userName = user == null ? null : user.getAddress() == null ? null : user.getAddress().getCity();
String userName = user?.address?.city
String userName = user?.name ?: "匿名用户"
def str = null println str?.length() println str ?: "空字符串"
|
4. 集合:比 Java Stream 简洁 10 倍
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| def list = [1, 2, 3, 4, 5]
def map = [name: "王五", age: 30, city: "上海"]
list.each { println it } list.each { num -> println "数字:${num}" }
def evenList = list.findAll { it % 2 == 0 } def squareList = list.collect { it * it } def sum = list.sum() def max = list.max() def first = list.find { it > 3 }
println map.name map.sex = "男" map.each { key, value -> println "${key}: ${value}" }
def rang = 1..10 def charRang = 'A'..'Z' rang.each { println "数字:${it}" }
|
5. 方法:简化写法
省略 return、分号、修饰符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| def add(int a, int b) { a + b }
println add 1, 2
def sayHello(String name, String msg = "你好") { "${msg},${name}" } println sayHello "赵六" println sayHello "赵六", "早上好"
def sayHi() { "Hi, Groovy!" } println sayHi
def javaUser = new JavaUser("张三", 25) println add javaUser.age, 5 println javaUser.getUserName()
|
6. 闭包(Closure):Groovy 的灵魂
闭包是“可传递的代码块”,相当于 Java 的 Lambda,但功能更强大,是 Groovy 动态特性的核心,也是 Java 项目集成 Groovy 实现动态扩展的关键。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| def closure = { String name -> println "Hello ${name},我是 Groovy 闭包" }
closure.call("Java 开发者") closure("Java 开发者")
def processList(List list, Closure closure) { list.each { closure(it) } }
processList([1,2,3]) { num -> println num * 2 }
def printItem = { println "元素:${it}" } printItem(100) processList([4,5,6], printItem)
|
四、Groovy 动态特性
Java 项目集成 Groovy 的核心价值,在于其动态特性——可在运行时动态执行脚本、添加属性/方法,实现业务逻辑的动态配置,无需重启服务。
1. 动态方法调用
运行时调用任意方法
1 2 3 4 5 6 7 8 9 10 11 12 13
| def user = new JavaUser("张三", 25)
user.setName("李四")
user."setName"("李四") def methodName = "setName" user."${methodName}"("李四")
def staticMethodName = "getStaticInfo" println JavaUser."${staticMethodName}"()
|
2. 运行时添加属性和方法
动态扩展 Java 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| def user = new JavaUser("张三", 25)
user.age = 25 user.sex = "男" println user.sex
user.sayHello = { println "我是 ${name},今年 ${age} 岁,性别:${sex}" } user.sayHello()
JavaUser.staticMethod = { "动态添加的 JavaUser 静态方法" } println JavaUser.staticMethod()
|
3. 运行 Groovy 脚本文件
生产环境中,常用“脚本文件”形式管理 Groovy 逻辑,Java 服务可动态加载脚本文件,修改脚本后无需重启服务,直接生效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import groovy.lang.GroovyClassLoader; import java.io.File;
public class GroovyFileLoader { public static void main(String[] args) throws Exception { GroovyClassLoader classLoader = new GroovyClassLoader();
File scriptFile = new File("src/main/resources/groovy/TestScript.groovy"); Class<?> scriptClass = classLoader.parseClass(scriptFile);
Object scriptInstance = scriptClass.newInstance(); Object result = scriptClass.getMethod("run").invoke(scriptInstance); System.out.println("脚本文件执行结果:" + result);
Object paramResult = scriptClass.getMethod("calculate", int.class, int.class) .invoke(scriptInstance, 10, 20); System.out.println("带参方法执行结果:" + paramResult); } }
def run() { "Groovy 脚本文件执行成功(Java 动态加载)" }
def calculate(int a, int b) { a + b }
def getUserInfo() { def user = new JavaUser("脚本用户", 30) return user.getUserName() }
|
五、生产环境集成
Java 项目集成 Groovy 后,需关注性能、安全、可维护性,以下是企业级生产环境的最佳实践。
1. 性能优化:预编译脚本 + 缓存
每次调用 GroovyShell.evaluate() 或 GroovyClassLoader.parseClass() 都会重新编译脚本,性能较差。生产环境建议“预编译脚本并缓存”,提升执行效率。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import groovy.lang.GroovyShell; import groovy.lang.Script; import java.util.Map; import java.util.concurrent.ConcurrentHashMap;
public class CachedGroovyScriptUtil { private static final Map<String, Script> SCRIPT_CACHE = new ConcurrentHashMap<>(); private static final GroovyShell GROOVY_SHELL = new GroovyShell();
public static Object executeScript(String scriptId, String scriptCode, Map<String, Object> params) { Script script = SCRIPT_CACHE.computeIfAbsent(scriptId, id -> GROOVY_SHELL.parse(scriptCode));
script.setBinding(null); params.forEach(script::setVariable);
return script.run(); }
public static void clearCache(String scriptId) { SCRIPT_CACHE.remove(scriptId); } }
|
2. 安全防护:沙箱模式
生产环境中,若脚本来自用户输入或外部配置,必须启用 Groovy 沙箱,限制脚本的执行权限,防止恶意脚本调用危险 API(如文件操作、网络请求、反射),避免安全漏洞。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import groovy.lang.GroovyShell; import org.codehaus.groovy.control.CompilerConfiguration; import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer; import org.kohsuke.groovy.sandbox.SandboxTransformer; import groovy.transform.ThreadInterrupt;
public class GroovySandboxUtil { private static final GroovyShell SANDBOX_GROOVY_SHELL;
static { CompilerConfiguration config = new CompilerConfiguration(); config.addCompilationCustomizers(new SandboxTransformer()); config.addCompilationCustomizers(new ASTTransformationCustomizer(ThreadInterrupt.class));
SANDBOX_GROOVY_SHELL = new GroovyShell(config);
}
public static Object executeSafeScript(String scriptCode, Map<String, Object> params) { params.forEach(SANDBOX_GROOVY_SHELL::setVariable); return SANDBOX_GROOVY_SHELL.evaluate(scriptCode); } }
|
3. 混合开发最佳实践
- ✅ 核心业务逻辑(如数据库操作、权限校验):用 Java 编写(类型安全、性能好、易维护)。
- ✅ 动态逻辑(如业务规则、计算表达式、配置解析):用 Groovy 编写(灵活、可动态修改)。
- ✅ 接口定义:用 Java 定义接口,Groovy 实现接口(兼顾接口规范和 Groovy 的简洁性)。
- ✅ 脚本管理:将 Groovy 脚本文件放在 resources 目录下,通过配置中心动态更新脚本,无需重启服务。
- ✅ 避免陷阱:复杂逻辑避免使用 Groovy 动态类型,优先使用静态类型,减少运行时类型错误;避免在 Groovy 中过度使用元编程,降低维护成本。
六、避坑指南
- 版本兼容坑:使用 Groovy 3.x 版本集成 Java 会报错,务必选择 Groovy 4.0.15+ 版本,且 Maven 依赖中指定 Java 源码和目标版本。
- 语法混淆坑:Groovy 中
== 等价于 Java 的 equals(),比较对象引用需用 is()(如 user1.is(user2)),避免误判。
- 性能坑:频繁调用
GroovyShell.evaluate() 会导致性能瓶颈,务必使用预编译 + 缓存(参考生产实践章节)。
- 安全坑:不启用沙箱直接执行外部脚本,会导致远程代码执行漏洞,生产环境必须集成 Groovy 沙箱。
- 互调坑:Groovy 调用 Java 类时,若 Java 类有重载方法,需明确指定参数类型,避免 Groovy 动态类型匹配错误。
- 日期 API 坑:Groovy 4.0+ 完全支持 Java 的
java.time API(如 LocalDate、LocalDateTime),避免使用 Groovy 旧日期 API,保持与 Java 一致。