Apache Groovy 快速入门与集成示例

从环境检查到首个 Groovy 程序,掌握闭包、GString 与集合操作;并给出与 Gradle、Spring Boot、普通 Java 动态执行 Groovy 的集成示例与真实输出。

Apache GroovyApache GroovyJavaApache2026/10/12

Apache Groovy 快速入门与集成示例

本文先以最小示例快速上手 Groovy,再给出与 Gradle、Spring Boot 及普通 Java 工程的集成样例。示例基于 Groovy 4.0.24 + JDK 11,命令与回显均来自真实执行。

一、快速入门

1.1 环境准备

确认 groovy 已可用,并设置好 JAVA_HOME:

# export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64   # CentOS: /usr/lib/jvm/java-11-openjdk
# export GROOVY_HOME=/opt/groovy
# export PATH=$GROOVY_HOME/bin:$JAVA_HOME/bin:$PATH
# groovy --version
Groovy Version: 4.0.24 JVM: 11.0.32.1 Vendor: Ubuntu OS: Linux

1.2 第一个程序

创建 Hello.groovy:

def name = "Groovy"
def nums = [1, 2, 3, 4, 5]
println "Hello, ${name}!"                       // GString 插值
println "doubled = ${nums.collect { it * 2 }}"  // 闭包 + 集合变换
println "total   = ${nums.sum()}"

运行:

# groovy Hello.groovy
Hello, Groovy!
doubled = [2, 4, 6, 8, 10]
total   = 15

1.3 逐行解读

  • def:动态类型声明,无需指定类型,运行时推断。
  • "Hello, ${name}!":GString,双引号内可嵌入表达式;单引号字符串不做插值。
  • nums.collect { it * 2 }:collect 接收闭包,对每个元素变换后返回新列表;it 是单参数闭包的隐式名。
  • nums.sum():Groovy 为集合扩展的聚合方法。

二、语言要点速览

2.1 闭包

def square = { int x -> x * x }
println square(9)
def adder = { a, b -> a + b }
println adder(3, 4)

2.2 GString 与安全导航

def maybe = null
println "safe len = ${maybe?.size()}"    // 安全导航,空对象不抛异常
println "elvis    = ${maybe ?: 'default'}"  // Elvis 运算符

2.3 集合与 Map

def nums = [1, 2, 3, 4, 5]
println nums.findAll { it % 2 == 0 }     // [2, 4]
println nums.every { it > 0 }            // true
def map = [k1: 'v1', k2: 'v2']
map.each { k, v -> println "map ${k} -> ${v}" }

2.4 正则与静态编译

def m = "order-2026-10-12.log" =~ /(\d{4})-(\d{2})-(\d{2})/
println m[0][0]
import groovy.transform.CompileStatic

@CompileStatic
int total(int[] xs) { xs.sum() as int }

三、Gradle 构建集成

3.1 工程结构

gradle-proj/
├── build.gradle
├── gradle.properties
└── src/main/groovy/App.groovy

3.2 构建脚本

build.gradle:

plugins { id 'groovy'; id 'application' }
repositories { mavenCentral() }
dependencies { implementation 'org.apache.groovy:groovy:4.0.24' }
application { mainClass = 'App' }

gradle.properties(控制构建 JVM 堆):

org.gradle.jvmargs=-Xmx512m

3.3 应用源码与运行

src/main/groovy/App.groovy:

class App {
    static void main(String[] args) {
        println "Hello from Gradle + Groovy ${GroovySystem.version}"
        def nums = [3, 1, 2, 5, 4]
        println "sorted = ${nums.sort()}"
    }
}

运行(Gradle 8.5):

# gradle run -q --no-daemon
Hello from Gradle + Groovy 4.0.24
sorted = [1, 2, 3, 4, 5]

四、Spring Boot 集成

Groovy 类可被 Spring 的 IoC 上下文直接扫描并作为 Bean 使用。

4.1 依赖坐标

<dependency>
  <groupId>org.apache.groovy</groupId>
  <artifactId>groovy</artifactId>
  <version>4.0.24</version>
</dependency>

4.2 Groovy 编写的 REST 组件(参考实现)

import org.springframework.web.bind.annotation.*
import groovy.transform.CompileStatic

@RestController
@CompileStatic
class GreetController {

    @GetMapping('/hello')
    String hello(@RequestParam(defaultValue = 'world') String name) {
        "Hello, ${name}!"
    }
}

将该文件放在 src/main/groovy 下,与 Java 代码同包结构,Spring Boot 启动后访问 /hello?name=apache 即返回 Hello, apache!。@CompileStatic 可让该控制器获得接近 Java 的运行性能。

说明:以上为集成骨架,依赖 Spring Boot 运行环境,未在本文所述命令行环境中单独运行。

五、普通 Java 中集成

5.1 GroovyShell 动态执行

Embed.java:

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

public class Embed {
    public static void main(String[] args) {
        GroovyShell shell = new GroovyShell();
        Object sum = shell.evaluate("(1..10).sum()");
        System.out.println("sum(1..10) = " + sum);
        shell.evaluate("println 'hello from embedded groovy'");

        Binding binding = new Binding();
        binding.setVariable("user", "apache");
        GroovyShell shell2 = new GroovyShell(binding);
        shell2.evaluate("greeting = \"Welcome, ${user}!\"");
        System.out.println("binding.greeting = " + binding.getVariable("greeting"));
    }
}

编译与运行:

# javac -encoding UTF-8 -cp /opt/groovy/lib/groovy-4.0.24.jar Embed.java -d .
# java -cp .:/opt/groovy/lib/groovy-4.0.24.jar Embed
sum(1..10) = 55
hello from embedded groovy
binding.greeting = Welcome, apache!

5.2 GroovyClassLoader 动态加载类

def gcl = new GroovyClassLoader()
def cls = gcl.parseClass('''
class Greeter {
    String hi(String name) { "Hello, ${name}!" }
}
''')
println cls.newInstance().hi('Groovy')
println "loaded class = ${cls.name}"

真实回显:

# groovy gcl.groovy
Hello, Groovy!
loaded class = Greeter
factorial(5) = 120

5.3 Binding 数据传递

Binding 是 Java 与 Groovy 的双向变量通道:Java 侧 setVariable 注入、脚本内直接读取;脚本内赋值的变量可通过 getVariable 取回,实现参数下发与结果回收。

六、常见问题

Q1:脚本中文乱码?

运行脚本时指定编码 groovy -c UTF-8 script.groovy;使用 Java 编译 Groovy 相关源码时加 -encoding UTF-8。

Q2:groovysh 输入后长时间无反应?

不要在根目录 / 启动,切换到业务目录再启动,避免类路径全盘递归扫描。

Q3:@Grab 拉取失败?

确认可访问 Maven Central,或通过 @GrabResolver 指向私有仓库;离线环境请预先缓存 ~/.groovy/grapes。

Q4:集成时出现 NoClassDefFoundError: groovy/lang/...?

运行时类路径缺少 Groovy 运行时 jar,请将 groovy-4.0.24.jar(或 Maven 坐标 org.apache.groovy:groovy)加入 classpath。