1、概览 {#1概览}
Groovy 是一种功能强大的动态 JVM 语言,具有众多特性。在 Spring 中使用 Groovy 可以大大提高应用程序的灵活性和可读性。从 Spring 4 开始 支持基于 Groovy 的配置。
在本教程中,我们将了解 Groovy 与 Spring 结合使用的各种方法。首先介绍了如何使用 Spring 提供的多个选项来创建 Groovy Bean 定义。接下来,了解如何使用 Groovy 脚本加载 Application Context。最后,学习如何使用 XML 和 GroovyScriptEngine
类将 Groovy 作为脚本执行(无需编译)。
2、Maven 依赖 {#2maven-依赖}
首先,在 pom.xml
中定义 Groovy 依赖:
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>3.0.12</version>
</dependency>
此外,还需要添加 GMavenPlus 插件来编译 Groovy 文件:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.9.0</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>
3、Bean 定义 {#3bean-定义}
传统上,开发人员通过 XML 配置来声明 Bean。这种方式后来被通过 Java 注解以编程方式定义 Bean 所取代。另一种声明 Bean 的方式是通过 Groovy 脚本。
由于我们使用的是 GMavenPlus 插件,Groovy 源文件可以与 src/main/java
源文件夹中的其他 Java 代码混合在一起。不过,最好还是将 Groovy 文件放在专用的 src/main/groovy
源文件夹中,以免后期出现混乱。
3.1、使用 Groovy Bean Builder {#31使用-groovy-bean-builder}
Groovy Bean Builder 是 Java 基于 @Configuration
注解的配置和基于 XML 的配置的强大替代品。如下,是一些基本的 Bean 定义的 Groovy 代码:
beans {
// 声明一个简单的 Bean,带有一个构造函数参数
company(Company, name: 'ABC Inc');
// 可以使用更简单的语法声明相同的 bean:beanName(type, constructor-args)
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')
}
如上,包含了所有 Bean 声明的 beans
结构是一个闭包,GroovyBeanDefinitionReader
将其作为 DSL 来处理。
3.2、使用注解 {#32使用注解}
Groovy 类也可以是有效的 Spring Bean,在基于注解的配置中,可以用 Groovy 代替 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 {#33使用-xml}
Groovy Bean Builder 和基于注解的配置都更加灵活。不过,我们仍然可以使用 XML 来声明在 Groovy 脚本中定义的 Bean。Groovy 是一种 动态语言,Spring 为其提供了全面的支持。首先需要在 XML 配置中使用一个特殊元素(<lang:groovy>
)来表示正在定义动态语言支持的 Bean。
例如,如下 XML 配置示例,它引用了正确的 schema,所以可以使用 lang
命名空间中的标签:
<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 脚本的 notification
Bean。可以使用 file
前缀指定脚本的确切位置。或者,也可以使用 classpath
前缀直接从 classpath 访问资源。refresh-check-delay
属性定义了脚本的刷新间隔,当脚本内容发生变化时,可以自动刷新。
4、加载 Application Context {#4加载-application-context}
Spring 需要知道如何加载 Groovy Context 文件,以使应用程序可以使用 Bean。可以通过在 web.xml
中进行配置或以编程方式加载 Context 来实现这一点。
4.1、在 web.xml 中添加 Groovy 配置 {#41在-webxml-中添加-groovy-配置}
Spring 4.1 使用 GroovyWebApplicationContext
增加了通过 web.xml
加载 Groovy 配置文件的支持。
默认情况下,配置将从 /WEB-INF/applicationContext.groovy
加载。这可以通过 contextConfigLocation
Servlet Context Parameter 重写该位置:
<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>
4.2、使用 GenericGroovyApplicationContext
{#42使用-genericgroovyapplicationcontext}
Spring 提供了 GenericGroovyApplicationContext
来加载 Groovy Bean 定义。此外,该 Context 可通过内联 Bean 定义闭包加载:
def context = new GenericGroovyApplicationContext()
context.reader.beans {
department(Department) {
name = 'Finance'
floor = 3
}
}
context.refresh()
或者,可以将此 Bean 定义外部化,并从 Groovy 配置文件中加载 Application Context:
GenericGroovyApplicationContext context = new GenericGroovyApplicationContext();
context.load("config/applicationContext.groovy");
context.refresh();
可以看到,加载 Groovy Context 的风格,与实例化 Java XmlWebApplicationContext
或 ClassPathXmlApplicationContext
的风格类似。
在没有额外配置的情况下,代码可以更加简洁:
ApplicationContext context = new GenericGroovyApplicationContext("config/applicationContext.groovy");
String foo = context.getBean("foo", String.class);
此外,GenericGroovyApplicationContext
还能理解 XML Bean 定义文件。这样就能与 Groovy Bean 定义文件进行无缝混合和匹配,从而增加了灵活性。
5、执行 Groovy 脚本 {#5执行-groovy-脚本}
除了 Groovy Bean 定义,Spring 还支持在不编译的情况下执行 Groovy 脚本。这种执行方式可以是独立的 Bean,也可以是在 Bean 中调用 Groovy 脚本,使脚本成为 Bean 的可执行部分。
5.1、内联脚本 {#51内联脚本}
如前所述,可以使用 Spring 提供的动态语言支持,将 Groovy 源文件直接嵌入 Spring Bean 定义中。因此,可以使用 <lang:inline-script/>
元素在 Spring 配置 XML 文件中定义 Groovy 源文件。
例如,可以使用内联脚本功能创建一个 Notifier
Bean:
<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
{#52使用-groovyscriptengine}
还可以使用 GroovyScriptEngine
类来执行 Groovy 脚本。GroovyScriptEngine
由 Groovy 本身提供,使用它无需依赖 Spring。
该类支持在脚本发生变化时自动重新加载脚本。此外,它还会加载所有依赖于它的类。
执行脚本有两种方法。一种是获取一个 GroovyObject
,然后通过调用 invokeMethod()
来执行脚本:
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());
另一种是直接调用 Groovy 脚本。使用 Binding
类将变量传递给 Groovy 脚本:
Binding binding = new Binding();
binding.setVariable("arg1", "Mr.");
binding.setVariable("arg2", "Bob");
Object result = engine.run("StringJoinerScript.groovy", binding);
assertEquals("Mr.Bob", result.toString());
6、总结 {#6总结}
在本文中,我们了解了 Spring 如何为 Groovy 提供广泛支持,从而使可以使用不同的方法获得有效的 Bean 定义。此外,还了解了如何将 Groovy 脚本加载为有效的 Spring Bean。最后,学习了如何即时调用 Groovy 脚本。
参考:https://www.baeldung.com/groovy/spring-using-groovy