1. 概述
Groovy 是一款强大的动态 JVM 语言,拥有众多特性。在 Spring 中使用 Groovy 能显著提升应用的灵活性和代码可读性。Spring 从 4.0 版本开始就支持基于 Groovy 的配置。
本文将探讨在 Spring 中集成 Groovy 的多种方式。我们将:
- 使用 Spring 提供的不同选项创建 Groovy Bean 定义
- 通过 Groovy 脚本引导应用上下文
- 使用 XML 和
GroovyScriptEngine
类直接执行 Groovy 脚本(无需编译)
2. Maven 依赖
首先在 pom.xml
中添加 Groovy 依赖:
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy</artifactId>
<version>4.0.21</version>
</dependency>
接着添加 GMavenPlus 插件编译 Groovy 文件:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<goals>
<goal>addSources</goal>
<goal>addTestSources</goal>
<goal>generateStubs</goal>
<goal>compile</goal>
<goal>generateTestStubs</goal>
<goal>compileTests</goal>
<goal>removeStubs</goal>
<goal>removeTestStubs</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
⚠️ 虽然 GMavenPlus 插件允许将 Groovy 文件放在
src/main/java
目录,但强烈建议使用专门的src/main/groovy
目录,避免后期维护混乱。
3. Bean 定义
传统开发中通过 XML 声明 Bean,后来被 Java 注解取代。现在我们还可以使用 Groovy 脚本定义 Bean。
3.1. 使用 Groovy Bean Builder
Groovy Bean Builder 是 Java @Configuration
和 XML 配置的强大替代方案。看几个基础示例:
beans {
// 使用构造参数声明简单 Bean
company(Company, name: 'ABC Inc');
// 更简洁的语法:beanName(type, 构造参数)
company String, 'ABC Inc'
// 声明 Employee 对象,通过 setter 引用前述 Bean
employee(Employee) {
firstName = 'Lakshmi'
lastName = 'Priya'
// 引用其他 Bean 的两种方式
vendor = company // 或 vendor = ref('company')
}
// 导入其他配置文件(支持 XML 和 Groovy)
importBeans('classpath:ApplicationContext.xml')
importBeans('classpath:GroovyContext.groovy')
}
顶层的
beans
闭包会被GroovyBeanDefinitionReader
解析为 DSL 语法。
3.2. 使用注解
Groovy 类也可以作为 Spring Bean,完全替代 Java 进行注解配置:
@Configuration
class SpringGroovyConfiguration{
@Bean
List<String> fruits() {
['Apple', 'Orange', 'Banana', 'Grapes']
}
@Bean
Map<Integer, String> rankings() {
[1: 'Gold', 2: 'Silver', 3: 'Bronze']
}
}
3.3. 使用 XML
虽然 Groovy Bean Builder 和注解更灵活,但仍可通过 XML 声明 Groovy 脚本中的 Bean。Groovy 是动态语言,Spring 提供了全面支持,**需在 XML 中使用特殊元素 <lang:groovy>
**:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang https://www.springframework.org/schema/lang/spring-lang.xsd">
<lang:groovy id="notification" script-source="file:NotificationServiceImpl.groovy" refresh-check-delay="10000" >
<lang:property name="message" value="Hello" />
</lang:groovy>
</beans>
关键属性说明:
script-source
:指定 Groovy 脚本位置file:
前缀 → 文件系统路径classpath:
前缀 → 类路径资源
refresh-check-delay
:脚本刷新间隔(毫秒),修改后自动重载
4. 引导应用上下文
Spring 需要知道如何加载 Groovy 配置文件。可通过 web.xml
或编程方式实现。
4.1. 在 web.xml 中添加 Groovy 配置
Spring 4.1 新增了通过 web.xml
加载 Groovy 配置的支持,借助 GroovyWebApplicationContext
:
<web-app>
...
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.GroovyWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/applicationContext.groovy</param-value>
</context-param>
...
</web-app>
默认加载
/WEB-INF/applicationContext.groovy
,可通过contextConfigLocation
覆盖路径。
4.2. 使用 GenericGroovyApplicationContext
Spring 提供 GenericGroovyApplicationContext
引导 Groovy Bean 定义,支持内联定义:
def context = new GenericGroovyApplicationContext()
context.reader.beans {
department(Department) {
name = 'Finance'
floor = 3
}
}
context.refresh()
或从外部文件加载:
GenericGroovyApplicationContext context = new GenericGroovyApplicationContext();
context.load("config/applicationContext.groovy");
context.refresh();
加载方式与
XmlWebApplicationContext
/ClassPathXmlApplicationContext
类似。无额外配置时更简洁:
ApplicationContext context = new GenericGroovyApplicationContext("config/applicationContext.groovy");
String foo = context.getBean("foo", String.class);
✅ 额外优势:GenericGroovyApplicationContext
兼容 XML Bean 定义文件,支持与 Groovy 配置无缝混用。
5. 执行 Groovy 脚本
除了 Bean 定义,Spring 还支持直接执行 Groovy 脚本(无需编译),可作为独立 Bean 或嵌入其他 Bean。
5.1. 作为内联脚本
利用 Spring 动态语言支持,将 Groovy 源码直接嵌入 XML 配置:
<lang:groovy id="notifier">
<lang:inline-script>
package com.baeldung.springgroovyconfig;
import com.baeldung.springgroovyconfig.NotificationService;
class Notifier implements NotificationService {
String message
}
</lang:inline-script>
<lang:property name="message" value="Have a nice day!" />
</lang:groovy>
5.2. 使用 GroovyScriptEngine
GroovyScriptEngine
是 Groovy 自带的类(不依赖 Spring),支持脚本修改后自动重载,并重新加载依赖类。
两种执行方式:
方式一:通过 GroovyObject 调用
GroovyScriptEngine engine = new GroovyScriptEngine(ResourceUtils.getFile("file:src/main/resources/")
.getAbsolutePath(), this.getClass().getClassLoader());
Class<GroovyObject> joinerClass = engine.loadScriptByName("StringJoiner.groovy");
GroovyObject joiner = joinerClass.newInstance();
Object result = joiner.invokeMethod("join", new Object[]{"Mr.", "Bob"});
assertEquals("Mr.Bob", result.toString());
方式二:直接调用脚本
Binding binding = new Binding();
binding.setVariable("arg1", "Mr.");
binding.setVariable("arg2", "Bob");
Object result = engine.run("StringJoinerScript.groovy", binding);
assertEquals("Mr.Bob", result.toString());
使用
Binding
类向脚本传递变量。
6. 总结
Spring 提供了丰富的 Groovy 集成方案。结合 Groovy 的动态特性和 Spring 的灵活性,能显著提升开发效率。本文我们学习了:
- ✅ 多种 Groovy Bean 定义方式(Bean Builder/注解/XML)
- ✅ 引导 Groovy 应用上下文的方法
- ✅ 动态执行 Groovy 脚本的技巧
示例代码可在 GitHub 获取。