Groovy 支持

在 Spring Integration 2.0 中,我们添加了 Groovy 支持,允许您使用 Groovy 脚本语言为各种集成组件提供逻辑——类似于 Spring 表达式语言 (SpEL) 支持路由、转换和其他集成问题的方式。有关 Groovy 的更多信息,请参阅 Groovy 文档,您可以在项目网站上找到。

您需要将此依赖项包含到您的项目中

  • Maven

  • Gradle

<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-groovy</artifactId>
    <version>6.3.5</version>
</dependency>
compile "org.springframework.integration:spring-integration-groovy:6.3.5"

此外,从 6.0 版本开始,提供了一个用于集成流配置的Groovy DSL

Groovy 配置

使用 Spring Integration 2.1,Groovy 支持的配置命名空间是 Spring Integration 脚本支持的扩展,并共享在脚本支持部分中详细描述的核心配置和行为。即使通用脚本支持很好地支持 Groovy 脚本,Groovy 支持也提供了Groovy配置命名空间,它由 Spring Framework 的org.springframework.scripting.groovy.GroovyScriptFactory和相关组件支持,提供了使用 Groovy 的扩展功能。以下列表显示了两个示例配置

过滤器
<int:filter input-channel="referencedScriptInput">
   <int-groovy:script location="some/path/to/groovy/file/GroovyFilterTests.groovy"/>
</int:filter>

<int:filter input-channel="inlineScriptInput">
     <int-groovy:script><![CDATA[
     return payload == 'good'
   ]]></int-groovy:script>
</int:filter>

如前面的示例所示,配置看起来与通用脚本支持配置相同。唯一的区别是使用了 Groovy 命名空间,如int-groovy命名空间前缀所示。另请注意,<script>标记上的lang属性在此命名空间中无效。

Groovy 对象自定义

如果您需要自定义 Groovy 对象本身(不仅仅是设置变量),您可以通过使用customizer属性引用实现GroovyObjectCustomizer的 bean。例如,如果您想通过修改MetaClass并注册可在脚本中使用的函数来实现领域特定语言 (DSL),这可能很有用。以下示例显示了如何操作

<int:service-activator input-channel="groovyChannel">
    <int-groovy:script location="somewhere/SomeScript.groovy" customizer="groovyCustomizer"/>
</int:service-activator>

<beans:bean id="groovyCustomizer" class="org.something.MyGroovyObjectCustomizer"/>

设置自定义GroovyObjectCustomizer<variable>元素或script-variable-generator属性并不相互排斥。在定义内联脚本时也可以提供它。

Spring Integration 3.0 引入了variables属性,它与variable元素一起使用。此外,如果未提供具有名称的绑定变量,Groovy 脚本能够将变量解析为BeanFactory中的 bean。以下示例显示了如何使用变量(entityManager

<int-groovy:script>
    <![CDATA[
        entityManager.persist(payload)
        payload
    ]]>
</int-groovy:script>

entityManager必须是应用程序上下文中的适当 bean。

有关<variable>元素、variables属性和script-variable-generator属性的更多信息,请参阅脚本变量绑定

Groovy 脚本编译器自定义

@CompileStatic提示是最受欢迎的 Groovy 编译器自定义选项。它可以在类或方法级别使用。有关更多信息,请参阅 Groovy参考手册,特别是@CompileStatic。为了在(集成场景中的)短脚本中使用此功能,我们被迫将简单的脚本更改为更类似 Java 的代码。考虑以下<filter>脚本

headers.type == 'good'

前面的脚本在 Spring Integration 中变为以下方法

@groovy.transform.CompileStatic
String filter(Map headers) {
	headers.type == 'good'
}

filter(headers)

这样,filter()方法就会被转换并编译为静态 Java 代码,绕过 Groovy 的动态调用阶段,例如getProperty()工厂和CallSite代理。

从 4.3 版本开始,您可以使用compile-staticboolean选项配置 Spring Integration Groovy 组件,指定应为@CompileStatic添加ASTTransformationCustomizer到内部CompilerConfiguration。有了它,您可以在我们的脚本代码中省略带有@CompileStatic的方法声明,并且仍然可以获得编译后的纯 Java 代码。在这种情况下,前面的脚本可以很短,但仍然需要比解释型脚本更冗长一些,如下例所示

binding.variables.headers.type == 'good'

您必须通过groovy.lang.Scriptbinding属性访问headerspayload(或任何其他)变量,因为使用@CompileStatic时,我们没有动态的GroovyObject.getProperty()功能。

此外,我们引入了compiler-configuration bean 引用。使用此属性,您可以提供任何其他所需的 Groovy 编译器自定义,例如ImportCustomizer。有关此功能的更多信息,请参阅 Groovy 文档,了解高级编译器配置

使用compilerConfiguration不会自动为@CompileStatic注释添加ASTTransformationCustomizer,它会覆盖compileStatic选项。如果您仍然需要CompileStatic,则应手动将new ASTTransformationCustomizer(CompileStatic.class)添加到该自定义compilerConfigurationCompilationCustomizers中。
Groovy 编译器自定义对refresh-check-delay选项没有任何影响,可重新加载的脚本也可以进行静态编译。

控制总线

如 (企业集成模式) 中所述,控制总线背后的思想是您可以将相同的消息系统用于监视和管理框架内的组件,就像用于“应用程序级”消息传递一样。在 Spring Integration 中,我们基于前面描述的适配器构建,以便您可以发送消息作为调用公开操作的一种方式。这些操作的一种选择是 Groovy 脚本。以下示例配置了控制总线的 Groovy 脚本

<int-groovy:control-bus input-channel="operationChannel"/>

控制总线有一个输入通道,可以访问它以调用应用程序上下文中的 bean 上的操作。

Groovy 控制总线在输入通道上运行消息作为 Groovy 脚本。它接收一条消息,将消息体编译成脚本,使用GroovyObjectCustomizer对其进行自定义,然后运行它。控制总线的MessageProcessor公开了应用程序上下文中的所有用@ManagedResource注释并实现 Spring 的Lifecycle接口或扩展 Spring 的CustomizableThreadCreator基类的 bean(例如,一些TaskExecutorTaskScheduler实现)。

小心在控制总线的命令脚本中使用具有自定义作用域(例如“请求”)的托管 bean,尤其是在异步消息流中。如果控制总线的MessageProcessor无法从应用程序上下文公开 bean,则在命令脚本运行期间可能会出现一些BeansException。例如,如果未建立自定义作用域的上下文,则尝试获取该作用域内的 bean 会触发BeanCreationException

如果您需要进一步自定义 Groovy 对象,您还可以通过customizer属性提供对实现GroovyObjectCustomizer的 bean 的引用,如下例所示

<int-groovy:control-bus input-channel="input"
        output-channel="output"
        customizer="groovyCustomizer"/>

<beans:bean id="groovyCustomizer" class="org.foo.MyGroovyObjectCustomizer"/>