|
如需使用最新稳定版本,请使用 Spring Integration 7.0.4! |
脚本支持
Spring Integration 2.1 增加了对 JSR223 Java 脚本规范 的支持,该规范在 Java 6 版本中引入。 它允许您使用任何受支持语言(包括 Ruby、JRuby、Groovy 和 Kotlin)编写的脚本来为各种集成组件提供逻辑,其方式类似于 Spring Expression Language (SpEL) 在 Spring Integration 中的使用方式。 有关 JSR223 的更多信息,请参阅 文档。
您需要将以下依赖项包含到您的项目中:
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-scripting</artifactId>
<version>6.4.10</version>
</dependency>
compile "org.springframework.integration:spring-integration-scripting:6.4.10"
此外,您需要添加一个脚本引擎实现,例如 JRuby。
从 5.2 版本开始,Spring Integration 提供了对 Kotlin Jsr223 的支持。 您需要将以下依赖项添加到项目中以使其生效:
-
Maven
-
Gradle
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-scripting-jsr223</artifactId>
<scope>runtime</scope>
</dependency>
runtime 'org.jetbrains.kotlin:kotlin-scripting-jsr223'
| 各种 JSR223 语言实现已由第三方开发。 特定实现与 Spring Integration 的兼容性取决于其符合规范的完善程度以及实施者对规范的理解。 |
| 如果您计划使用 Groovy 作为脚本语言,我们推荐使用 Spring-Integration 的 Groovy 支持,因为它提供了针对 Groovy 的额外功能。 不过,本节内容同样相关。 |
脚本配置
根据您的集成需求的复杂程度,脚本可以以 XML 配置中的 CDATA 形式内联提供,或者作为包含该脚本的 Spring 资源的引用。
要启用脚本支持,Spring Integration 定义了一个 ScriptExecutingMessageProcessor,它将消息负载绑定到名为 payload 的变量,并将消息头绑定到 headers 变量,两者均可在脚本执行上下文中访问。
您只需编写使用这些变量的脚本即可。
以下示例对展示了创建过滤器的示例配置:
-
Java DSL
-
XML
@Bean
public IntegrationFlow scriptFilter() {
return f -> f.filter(Scripts.processor("some/path/to/ruby/script/RubyFilterTests.rb"));
}
...
@Bean
public Resource scriptResource() {
return new ByteArrayResource("headers.type == 'good'".getBytes());
}
@Bean
public IntegrationFlow scriptFilter() {
return f -> f.filter(Scripts.processor(scriptResource()).lang("groovy"));
}
<int:filter input-channel="referencedScriptInput">
<int-script:script location="some/path/to/ruby/script/RubyFilterTests.rb"/>
</int:filter>
<int:filter input-channel="inlineScriptInput">
<int-script:script lang="groovy">
<![CDATA[
return payload == 'good'
]]>
</int-script:script>
</int:filter>
如前面的示例所示,脚本可以内联包含,也可以通过引用资源位置来包含(使用 location 属性)。
此外,lang 属性对应于语言名称(或其 JSR223 别名)。
其他支持脚本的 Spring Integration 端点元素包括 router、service-activator、transformer 和 splitter。
每种情况下的脚本配置均与上述内容相同(除端点元素外)。
脚本支持的另一个有用功能是能够在不重启应用上下文的情况下更新(重新加载)脚本。
为此,请在 script 元素上指定 refresh-check-delay 属性,如下示例所示:
-
Java DSL
-
XML
Scripts.processor(...).refreshCheckDelay(5000)
}
<int-script:script location="..." refresh-check-delay="5000"/>
在上面的示例中,脚本位置每 5 秒检查一次更新。 如果脚本已更新,则在更新后超过 5 秒发生的任何调用将导致运行新脚本。
考虑以下示例:
-
Java DSL
-
XML
Scripts.processor(...).refreshCheckDelay(0)
}
<int-script:script location="..." refresh-check-delay="0"/>
在前面的示例中,上下文会在发生任何脚本修改时立即更新,从而提供一种简单的“实时”配置机制。 任何负值都表示在应用上下文初始化后不会重新加载脚本。 这是默认行为。 以下示例展示了一个永不更新的脚本:
-
Java DSL
-
XML
Scripts.processor(...).refreshCheckDelay(-1)
}
<int-script:script location="..." refresh-check-delay="-1"/>
| 内联脚本无法重新加载。 |
脚本变量绑定
需要变量绑定,以使脚本能够引用外部提供给脚本执行上下文的变量。
默认情况下,payload 和 headers 被用作绑定变量。
您可以使用 <variable> 元素(或 ScriptSpec.variables() 选项)将额外的变量绑定到脚本中,如下示例所示:
-
Java DSL
-
XML
Scripts.processor("foo/bar/MyScript.py")
.variables(Map.of("var1", "thing1", "var2", "thing2", "date", date))
}
<script:script lang="py" location="foo/bar/MyScript.py">
<script:variable name="var1" value="thing1"/>
<script:variable name="var2" value="thing2"/>
<script:variable name="date" ref="date"/>
</script:script>
如前例所示,您可以将脚本变量绑定到标量值或 Spring Bean 引用。
请注意,payload和headers仍作为绑定变量包含在内。
随着 Spring Integration 3.0 的发布,除了 variable 元素外,还引入了 variables 属性。
该属性与 variable 元素并非互斥,您可以在同一个 script 组件中组合使用它们。
然而,无论变量在何处定义,其名称必须唯一。
此外,自 Spring Integration 3.0 起,内联脚本也允许进行变量绑定,如下示例所示:
<service-activator input-channel="input">
<script:script lang="ruby" variables="thing1=THING1, date-ref=dateBean">
<script:variable name="thing2" ref="thing2Bean"/>
<script:variable name="thing3" value="thing2"/>
<![CDATA[
payload.foo = thing1
payload.date = date
payload.bar = thing2
payload.baz = thing3
payload
]]>
</script:script>
</service-activator>
前面的示例展示了内联脚本、variable元素和variables属性的组合。
variables属性包含逗号分隔的值,其中每个段包含一个由'='分隔的变量及其值的对。
变量名可以后缀-ref,如前面示例中的date-ref变量所示。
这意味着绑定变量的名称为date,但其值是应用程序上下文中dateBeanbean的引用。
在使用属性占位符配置或命令行参数时,这可能非常有用。
如果您需要更精细地控制变量的生成方式,您可以实现自己的 Java 类,该类使用 ScriptVariableGenerator 策略,该策略由以下接口定义:
public interface ScriptVariableGenerator {
Map<String, Object> generateScriptVariables(Message<?> message);
}
此接口要求您实现 generateScriptVariables(Message) 方法。
消息参数允许您访问消息负载和标头中可用的任何数据,返回值是绑定变量的 Map。
每次为消息执行脚本时都会调用此方法。
以下示例展示了如何实现 ScriptVariableGenerator 并使用 script-variable-generator 属性引用它:
-
Java DSL
-
XML
Scripts.processor("foo/bar/MyScript.groovy")
.variableGenerator(new foo.bar.MyScriptVariableGenerator())
}
<int-script:script location="foo/bar/MyScript.groovy"
script-variable-generator="variableGenerator"/>
<bean id="variableGenerator" class="foo.bar.MyScriptVariableGenerator"/>
如果未提供 script-variable-generator,脚本组件将使用 DefaultScriptVariableGenerator,该值会将任何提供的 <variable> 元素与来自 Message 的 payload 和 headers 变量在其 generateScriptVariables(Message) 方法中进行合并。
您不能同时提供 script-variable-generator 属性和 <variable> 元素。它们是互斥的。 |
GraalVM 多语言支持
从版本 6.0 开始,该框架提供了一个基于 GraalVM 多语言 API 的 PolyglotScriptExecutor。
原本由 Java 自身移除的 JavaScript JSR223 引擎实现,现已通过使用此新的脚本执行器进行替代。
有关在 GraalVM 中启用 JavaScript 支持的更多信息,以及可通过脚本变量传递的哪些 配置选项,请参阅相关文档。
特别是,为了支持 JavaScript,必须在目标项目中添加 org.graalvm.polyglot:js 依赖项。
从版本 6.4 开始,Python 脚本支持也已迁移至 GraalVM Polyglot。
现在这些脚本可以使用 Python 3.x 编写,并能够使用第三方库。
有关更多信息,请参阅 GraalPy 文档。
特别是,需要为目标项目添加 rg.graalvm.polyglot:python 依赖以支持 Python。
默认情况下,框架在共享的多语言 Context 上将 allowAllAccess 设置为 true,从而实现与主机 JVM 的交互:
-
新线程的创建和使用。
-
访问公共主机类。
-
通过向类路径添加条目来加载新的主机类。
-
正在将新成员导出到多语言绑定中。
-
主机系统上的不受限制的 IO 操作。
-
传递实验性选项。
-
新子进程的产生与使用。
-
访问进程环境变量。
这可以通过重载的 PolyglotScriptExecutor 构造函数进行自定义,该构造函数接受一个 org.graalvm.polyglot.Context.Builder。
例如,基于 Jython 的脚本仍然可以使用 option("python.EmulateJython", "true") 执行。
然而,建议完全迁移到 GraalPy 以获得更好的解释性能。
因此,用于 Java 类的 import 不再起作用,必须改用 import java 及其相应的 java.type() 函数。