控制总线

正如 企业集成模式 (EIP) 一书中所述,控制总线背后的理念是,用于监控和管理框架内组件的消息系统可以与用于“应用层”消息传递的系统相同。 在 Spring Integration 中,我们基于上述适配器进行构建,以便您可以发送消息作为调用公开操作的手段。

由于控制总线功能强大,足以更改系统状态,因此建议保护其消息接收(参见 SecurityContextChannelInterceptor),并且仅在 DMZ 中公开控制总线管理(消息源)。

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

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

控制总线有一个输入通道,可以通过该通道访问以调用应用程序上下文中 bean 上的操作。 它还具有服务激活端点的所有常见属性。 例如,如果操作结果具有您想要发送到下游通道的返回值,您可以指定一个输出通道。

控制总线以简单的字符串格式(如 beanName.methodName)将输入通道上的消息作为托管操作运行。 目标方法参数的参数必须作为列表在 IntegrationMessageHeaderAccessor.CONTROL_BUS_ARGUMENTS 头中提供。 要调用的 bean 和方法从 ControlBusCommandRegistry 基础设施 bean 中解析。 默认情况下,ControlBusCommandRegistry 按需注册命令:其 eagerInitialization 标志可以通过 @EnableIntegrationManagement(loadControlBusCommands = "true") 打开。

控制总线的功能类似于 JMX,因此方法作为命令的资格必须符合以下要求:

  • 使用 @ManagedAttribute@ManagedOperation 注解的方法;

  • Spring 的 Lifecycle 接口(及其自 5.2 版本以来的 Pausable 扩展);

  • 用于配置 Spring 的几种 TaskExecutorTaskScheduler 实现的方法。

确保您自己的方法可用于控制总线的最简单方法是使用 @ManagedAttribute@ManagedOperation 注解。 由于这些注解也用于将方法公开给 JMX MBean 注册表,因此它们提供了一个方便的副产品:通常,您希望公开给控制总线的同类型操作也适合通过 JMX 公开)。 有关更多信息,请参阅 ControlBusCommandRegistryControlBusMethodFilter 的 Javadoc。

要执行 Spring Bean 上的方法,客户端可以向操作通道发送消息,如下所示:

Message<?> operation = MessageBuilder.withPayload("myServiceBean.shutdown").build();
operationChannel.send(operation);

如果目标方法有参数(例如 ThreadPoolTaskExecutor.setMaxPoolSize(int maxPoolSize)),这些值必须作为 IntegrationMessageHeaderAccessor.CONTROL_BUS_ARGUMENTS 头提供:

Message<?> operation =
        MessageBuilder.withPayload("myTaskExecutor.setMaxPoolSize")
        .setHeader(IntegrationMessageHeaderAccessor.CONTROL_BUS_ARGUMENTS, List.of(10))
        .build();
operationChannel.send(operation);

您可以将这些命令视为 JDBC 中带有参数绑定的 PreparedStatement 实例。 参数的类型必须与方法参数的类型匹配。 它们被用作附加标准,根据 Java 方法重载特性选择要调用的方法。 例如,组件:

@ManagedResource
class TestManagementComponent {

    @ManagedOperation
    public void operation() {

    }

    @ManagedOperation(description = "The overloaded operation with int argument")
    public void operation(int input) {

    }

    @ManagedOperation(description = "The overloaded operation with two arguments")
    public void operation(int input1, String input2) {

    }

    @ManagedOperation
    public int operation2() {
    	return 123;
    }

}

将公开 3 个名为 operation 的命令。 当我们调用 testManagementComponent.operation 命令时,我们应该为 IntegrationMessageHeaderAccessor.CONTROL_BUS_ARGUMENTS 头选择一个适当的值列表,以便 ControlBusCommandRegistry 能够筛选出 bean 上的目标方法。

使用 Java 注解,您可以如下配置控制总线:

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

类似地,您可以如下配置 Java DSL 流定义:

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

如果您更喜欢使用带有自动 DirectChannel 创建的 lambda,您可以如下创建控制总线:

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

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

此外,请参阅 控制总线 REST 控制器,了解如何通过 HTTP 公开控制总线管理。