Groovy support

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
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-groovy</artifactId>
    <version>5.2.5.RELEASE</version>
</dependency>
Gradle
compile "org.springframework.integration:spring-integration-groovy:5.2.5.RELEASE"

Groovy Configuration

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:

Example 1. Filter
<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>

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

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"/>

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 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 must be an appropriate bean in the application context.

For more information regarding the <variable> element, the variables attribute, and the script-variable-generator attribute, see Script Variable Bindings.

Groovy Script Compiler Customization

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'

The preceding script becomes the following method in Spring Integration:

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

filter(headers)

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.

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'

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.

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 compilerConfiguration does not automatically add an ASTTransformationCustomizer for the @CompileStatic annotation, and it overrides the compileStatic option. If you still need CompileStatic, you should manually add a new ASTTransformationCustomizer(CompileStatic.class) into the CompilationCustomizers of that custom compilerConfiguration.
The Groovy compiler customization does not have any effect on the refresh-check-delay option, and reloadable scripts can be statically compiled, too.

Control Bus

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"/>

The control bus has an input channel that can be accessed to invoke operations on the beans in the application context.

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).

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.

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"/>