Control Bus

Enterprise Integration Patterns (EIP)书中所述,控制总线背后的想法是,可以将相同的邮件系统用于监控和管理框架内的组件,就像用于 “application-level” 邮件一样。在 Spring 集成中,我们在上面介绍的适配器的基础上构建,以便您可以发送邮件作为调用公开操作的一种方式。

As described in the Enterprise Integration Patterns (EIP) book, the idea behind the control bus is that the same messaging system can be used 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 above so that you can send messages as a means of invoking exposed operations.

以下示例演示了如何使用 XML 配置控制总线:

The following example shows how to configure a control bus with XML:

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

控制总线有一个输入通道,可以访问该通道来调用应用程序上下文中 Bean 上的操作。它还具有服务激活端点的所有通用特性。例如,如果你想发送操作结果到下游通道,你可以指定一个输出通道。

The control bus has an input channel that can be accessed for invoking operations on the beans in the application context. It also has all the common properties of a service activating endpoint. For example, you can specify an output channel if the result of the operation has a return value that you want to send on to a downstream channel.

控制总线在输入通道上以 Spring 表达式语言 (SpEL) 表达式的形式运行消息。它接收一条消息,将正文编译为一个表达式,添加一些上下文,然后运行它。默认上下文支持任何已使用 @ManagedAttribute@ManagedOperation 注释的方法。它还支持 Spring 的 Lifecycle 接口(以及自版本 5.2 起的其 Pausable 扩展)上的方法,同时还支持用于配置多个 Spring 的 TaskExecutorTaskScheduler 实现的方法。确保你自己的方法可供控制总线使用最简单的方法是使用 @ManagedAttribute@ManagedOperation 注释。由于这些注释还用于将方法公开给 JMX MBean 注册表,因此它们提供了一个便捷的副产品:通常,你想向控制总线公开的与你想要通过 JMX 公开的方法是合理的。在应用程序上下文中的任何特定实例的解析是通过典型的 SpEL 语法实现的。要做到这一点,请为 Bean 提供带有 Bean 的 SpEL 前缀 (@)。例如,为了在 Spring Bean 上执行一个方法,客户端可以按照如下方式将消息发送到操作通道:

The control bus runs messages on the input channel as Spring Expression Language (SpEL) expressions. It takes a message, compiles the body to an expression, adds some context, and then runs it. The default context supports any method that has been annotated with @ManagedAttribute or @ManagedOperation. It also supports the methods on Spring’s Lifecycle interface (and its Pausable extension since version 5.2), and it supports methods that are used to configure several of Spring’s TaskExecutor and TaskScheduler implementations. The simplest way to ensure that your own methods are available to the control bus is to use the @ManagedAttribute or @ManagedOperation annotations. Since those annotations are also used for exposing methods to a JMX MBean registry, they offer a convenient by-product: Often, the same types of operations you want to expose to the control bus are reasonable for exposing through JMX). Resolution of any particular instance within the application context is achieved in the typical SpEL syntax. To do so, provide the bean name with the SpEL prefix for beans (@). For example, to execute a method on a Spring Bean, a client could send a message to the operation channel as follows:

Message operation = MessageBuilder.withPayload("@myServiceBean.shutdown()").build();
operationChannel.send(operation)

上下文的根是 Message 本身,因此你还可以访问 payloadheaders 作为表达式中的变量。这与 Spring Integration 端点中的所有其他表达式支持一致。

The root of the context for the expression is the Message itself, so you also have access to the payload and headers as variables within your expression. This is consistent with all the other expression support in Spring Integration endpoints.

使用 Java 注释,可以按如下方式配置控制总线:

With Java annotations, you can configured the control bus as follows:

@Bean
@ServiceActivator(inputChannel = "operationChannel")
public ExpressionControlBusFactoryBean controlBus() {
    return new ExpressionControlBusFactoryBean();
}

同样地,你可以按如下方式配置 Java DSL 流定义:

Similarly, you can configure Java DSL flow definitions as follows:

@Bean
public IntegrationFlow controlBusFlow() {
    return IntegrationFlow.from("controlBus")
              .controlBus()
              .get();
}

如果你喜欢使用具有自动 DirectChannel 创建功能的 lambda,你可以按如下方式创建控制总线:

If you prefer to use lambdas with automatic DirectChannel creation, you can create a control bus as follows:

@Bean
public IntegrationFlow controlBus() {
    return IntegrationFlowDefinition::controlBus;
}

在这种情况下,通道被命名为 controlBus.input

In this case, the channel is named controlBus.input.