Groovy Support
在 Spring Integration 2.0 中,我们添加了 Groovy 支持,以便你可以使用 Groovy 脚本语言为各种集成组件提供逻辑,类似于 Spring 表达式语言 (SpEL) 受支持用于路由、转换和其他集成问题的方式。有关 Groovy 的更多信息,请参阅 Groovy 文档,你可以在 project website 中找到它。
In Spring Integration 2.0, we added Groovy support, letting you use the Groovy scripting language to provide the logic for various integration components — similar to the way the Spring Expression Language (SpEL) is supported for routing, transformation, and other integration concerns. For more information about Groovy, see the Groovy documentation, which you can find on the project website.
你需要将此依赖项包含在你的项目中:
You need to include this dependency into your project:
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-groovy</artifactId>
<version>{project-version}</version>
</dependency>
compile "org.springframework.integration:spring-integration-groovy:{project-version}"
此外,从 6.0 版本开始,为集成流程配置提供 Groovy DSL 。
In addition, starting with version 6.0, a Groovy DSL for integration flow configurations is provided.
Groovy Configuration
使用 Spring Integration 2.1,groovy 支持的配置命名空间是 Spring Integration 脚本支持的扩展,并且共享 Scripting Support 部分中详细描述的核心配置和行为。尽管 groovy 脚本得到了通用脚本支持的充分支持,但 groovy 支持提供了 Groovy
配置命名空间,该命名空间受 Spring Framework 的 org.springframework.scripting.groovy.GroovyScriptFactory
及相关组件的支持,为使用 groovy 提供了扩展功能。以下列表显示两个示例配置:
With Spring Integration 2.1, the configuration namespace for the Groovy support is an extension of Spring Integration’s scripting support and shares the core configuration and behavior described in detail in the Scripting Support section.
Even though Groovy scripts are well-supported by generic scripting support, the Groovy support provides the Groovy
configuration namespace, which is backed by the Spring Framework’s org.springframework.scripting.groovy.GroovyScriptFactory
and related components, offering extended capabilities for using Groovy.
The following listing shows two sample configurations:
<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
属性在此命名空间中无效。
As the preceding examples show, the configuration looks identical to the general scripting support configuration.
The only difference is the use of the Groovy namespace, as indicated by the int-groovy
namespace prefix.
Also note that the lang
attribute on the <script>
tag is not valid in this namespace.
Groovy Object Customization
如果你需要自定义 Groovy 对象本身(不仅限于设置变量),可以使用 customizer
属性引用一个实现 GroovyObjectCustomizer
的 Bean。例如,如果你想通过修改 MetaClass
并注册要在脚本中可用的函数来实现特定于域的语言 (DSL),这可能很有用。以下示例展示了如何进行此操作:
If you need to customize the Groovy object itself (beyond setting variables) you can reference a bean that implements GroovyObjectCustomizer
by using the customizer
attribute.
For example, this might be useful if you want to implement a domain-specific language (DSL) by modifying the MetaClass
and registering functions to be available within the script.
The following example shows how to do so:
<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
属性并不互斥。在定义内联脚本时也可以提供它。
Setting a custom GroovyObjectCustomizer
is not mutually exclusive with <variable>
elements or the script-variable-generator
attribute.
It can also be provided when defining an inline script.
Spring Integration 3.0 引入了 variables
属性,该属性与 variable
元素一起使用。此外,如果未提供名称的绑定变量,Groovy 脚本有能力将变量解析为 BeanFactory
中的 Bean。以下示例展示了如何使用变量 (entityManager
):
Spring Integration 3.0 introduced the variables
attribute, which works in conjunction with the variable
element.
Also, groovy scripts have the ability to resolve a variable to a bean in the BeanFactory
, if a binding variable was not provided with the name.
The following example shows how to use a variable (entityManager
):
<int-groovy:script>
<![CDATA[
entityManager.persist(payload)
payload
]]>
</int-groovy:script>
entityManager
必须是应用程序上下文中的合适 Bean。
entityManager
must be an appropriate bean in the application context.
有关 `<variable>`元素、`variables`属性和 `script-variable-generator`属性的更多信息,请参见 Script Variable Bindings。
For more information regarding the <variable>
element, the variables
attribute, and the script-variable-generator
attribute, see Script Variable Bindings.
Groovy Script Compiler Customization
`@CompileStatic`提示是最流行的 Groovy 编译器自定义选项。它可以在类级或方法级使用。有关详细信息,请参见 Groovy Reference Manual和,具体来说, @CompileStatic。若要将此功能用于短脚本(在集成场景中),我们被迫将简单的脚本更改为更类似于 Java 的代码。考虑以下 `<filter>`脚本:
The @CompileStatic
hint is the most popular Groovy compiler customization option.
It can be used on the class or method level.
For more information, see the Groovy Reference Manual and, specifically, @CompileStatic.
To utilize this feature for short scripts (in integration scenarios), we are forced to change simple scripts to more Java-like code.
Consider the following <filter>
script:
headers.type == 'good'
前面的脚本将变成 Spring Integration 中的以下方法:
The preceding script becomes the following method in Spring Integration:
@groovy.transform.CompileStatic
String filter(Map headers) {
headers.type == 'good'
}
filter(headers)
这样,filter()
方法就被转换为静态 Java 代码并编译,从而绕过了 Groovy 动态调用阶段,如 getProperty()
工厂和 CallSite
代理。
With that, the filter()
method is transformed and compiled to static Java code, bypassing the Groovy
dynamic phases of invocation, such as getProperty()
factories and CallSite
proxies.
从 4.3 版开始,你可以使用 compile-static
boolean
选项配置 Spring Integration Groovy 组件,该选项指定应将 @CompileStatic
的 ASTTransformationCustomizer
添加到内部 CompilerConfiguration
。这样做后,你可以在我们的脚本代码中省略带 @CompileStatic
的方法声明,并且仍然可以获取已编译的纯 Java 代码。在这种情况下,前面的脚本可以很短,但仍然需要比解释脚本更详细,如下面的示例所示:
Starting with version 4.3, you can configure the Spring Integration Groovy components with the compile-static
boolean
option, specifying that ASTTransformationCustomizer
for @CompileStatic
should be added to the internal CompilerConfiguration
.
With that in place, you can omit the method declaration with @CompileStatic
in our script code and still get compiled plain Java code.
In this case, the preceding script can be short but still needs to be a little more verbose than interpreted script, as the following example shows:
binding.variables.headers.type == 'good'
你必须通过 groovy.lang.Script
binding
属性访问 headers
和 payload
(或任何其他)变量,因为使用 @CompileStatic
时,我们没有动态 GroovyObject.getProperty()
功能。
You must access the headers
and payload
(or any other) variables through the groovy.lang.Script
binding
property because, with @CompileStatic
, we do not have the dynamic GroovyObject.getProperty()
capability.
此外,我们引入了 compiler-configuration
bean 引用。有了此属性,你可以提供任何其他所需的 Groovy 编译器自定义项,例如 ImportCustomizer
。有关此功能的更多信息,请参阅 groovy 文档中的 advanced compiler configuration 。
In addition, we introduced the compiler-configuration
bean reference.
With this attribute, you can provide any other required Groovy compiler customizations, such as ImportCustomizer
.
For more information about this feature, see the Groovy Documentation for advanced compiler configuration.
使用 |
Using |
Groovy 编译器定制对 |
The Groovy compiler customization does not have any effect on the |
Control Bus
如 ( Enterprise Integration Patterns) 中所述,控制总线的理念是,你可以使用与 "`application-level`"消息传递相同的用于在框架内监视和管理组件的消息传递系统。在 Spring Integration 中,我们基于前面描述的适配器,以便你可以发送消息作为调用已公开操作的一种方式。这些操作的一个选项是 Groovy 脚本。以下示例为控制总线配置了 Groovy 脚本:
As described in (Enterprise Integration Patterns), the idea behind the control bus is that you can use the same messaging system for monitoring and managing the components within the framework as is used for “application-level” messaging. In Spring Integration, we build upon the adapters described earlier so that you can send Messages as a means of invoking exposed operations. One option for those operations is Groovy scripts. The following example configures a Groovy script for the control bus:
<int-groovy:control-bus input-channel="operationChannel"/>
控制总线具有可用于在应用程序上下文中调用 Bean 上的操作的输入通道。
The control bus has an input channel that can be accessed to invoke operations on the beans in the application context.
Groovy 控制总线作为 Groovy 脚本在输入通道上运行消息。它获取消息,将主体编译为脚本,使用 GroovyObjectCustomizer
对其进行自定义,然后运行它。控制总线的 MessageProcessor
公开应用程序上下文中所有使用 @ManagedResource
注释并实现 Spring 的 Lifecycle
接口或扩展 Spring 的 CustomizableThreadCreator
基类的 Bean(例如,一些 TaskExecutor
和 TaskScheduler
实现)。
The Groovy control bus runs messages on the input channel as Groovy scripts.
It takes a message, compiles the body to a script, customizes it with a GroovyObjectCustomizer
, and runs it.
The control bus' MessageProcessor
exposes all beans in the application context that are annotated with @ManagedResource
and implement Spring’s Lifecycle
interface or extend Spring’s CustomizableThreadCreator
base class (for example, several of the TaskExecutor
and TaskScheduler
implementations).
请小心在控制总线命令脚本(尤其是在异步消息流中)中将托管 Bean 与自定义范围(例如“请求”)结合使用。如果控制总线 MessageProcessor
无法从应用程序上下文中公开 Bean,则可能最终会在执行命令脚本期间遇到 BeansException
。例如,如果未建立自定义范围的上下文,则在该范围内获取 Bean 的尝试将触发 BeanCreationException
。
Be careful about using managed beans with custom scopes (such as 'request') in the Control Bus' command scripts, especially inside an asynchronous message flow.
If MessageProcessor
of the control bus cannot expose a bean from the application context, you may end up with some BeansException
during the command script’s run.
For example, if a custom scope’s context is not established, the attempt to get a bean within that scope triggers a BeanCreationException
.
如果你需要进一步自定义 Groovy 对象,还可以通过 customizer
属性提供对实现 GroovyObjectCustomizer
的 Bean 的引用,如下面的例子所示:
If you need to further customize the Groovy objects, you can also provide a reference to a bean that implements GroovyObjectCustomizer
through the customizer
attribute, as the following example shows:
<int-groovy:control-bus input-channel="input"
output-channel="output"
customizer="groovyCustomizer"/>
<beans:bean id="groovyCustomizer" class="org.foo.MyGroovyObjectCustomizer"/>