# 系统管理

# 系统管理

# 指标和管理

本节描述如何捕获 Spring 集成的指标。在最近的版本中,我们更多地依赖于 Micrometer(参见https://micrometer.io (opens new window)),并且我们计划在未来的版本中更多地使用 Micrometer。

# 遗留指标

旧的度量标准在版本 5.4 中被删除;请参见下面的 Micrometer 集成。

# 在大容量环境中禁用日志记录

你可以在主消息流中控制调试日志记录。在非常大容量的应用程序中,对isDebugEnabled()的调用在一些日志记录子系统中可能非常昂贵。你可以禁用所有这样的日志记录,以避免这种开销。异常日志记录(调试或其他方式)不受此设置的影响。

下面的清单显示了用于控制日志记录的可用选项:

爪哇

@Configuration
@EnableIntegration
@EnableIntegrationManagement(
    defaultLoggingEnabled = "true" <1>)

public static class ContextConfiguration {
...
}

XML

<int:management default-logging-enabled="true"/> (1)
1 设置为false以禁用主消息流中的所有日志记录,无论日志系统的类别设置如何。
设置为“true”,以启用调试日志记录(如果还启用了日志记录子系统)。
仅当你没有在 Bean 定义中显式配置该设置时才应用。
默认值为true
defaultLoggingEnabled仅在未在 Bean 定义中显式配置相应设置的情况下才应用。

# 千分尺积分

# 概述

从版本 5.0.3 开始,在应用程序上下文中出现Micrometer (opens new window)MeterRegistry会触发对千分尺指标的支持。

要使用 Micrometer,将MeterRegistrybean 中的一个添加到应用程序上下文中。

对于每个MessageH和lerMessageChannel,计时器被注册。对于每个MessageSource,注册一个计数器。

这仅适用于扩展AbstractMessageHandlerAbstractMessageChannelAbstractMessageSource的对象(大多数框架组件都是这种情况)。

用于在消息通道上进行发送操作的Timer计具有以下名称或标记:

  • name: spring.integration.send

  • tag: type:channel

  • tag: name:<componentName>

  • tag: result:(success|failure)

  • tag: exception:(none|exception simple class name)

  • description: Send processing time

(带有none异常的failure结果表示通道的send()操作返回false

用于在可匹配消息通道上进行接收操作的Counter计具有以下名称或标记:

  • name: spring.integration.receive

  • tag: type:channel

  • tag: name:<componentName>

  • tag: result:(success|failure)

  • tag: exception:(none|exception simple class name)

  • description: Messages received

用于消息处理程序上的操作的Timer表具有以下名称或标记:

  • name: spring.integration.send

  • tag: type:handler

  • tag: name:<componentName>

  • tag: result:(success|failure)

  • tag: exception:(none|exception simple class name)

  • description: Send processing time

消息源的Counter表具有以下名称/标记:

  • name: spring.integration.receive

  • tag: type:source

  • tag: name:<componentName>

  • tag: result:success

  • tag: exception:none

  • description: Messages received

此外,还有三个Gauge米:

  • spring.integration.channels:应用程序中MessageChannels的数量。

  • spring.integration.handlers:应用程序中MessageHandlers的数量。

  • spring.integration.sources:应用程序中MessageSources的数量。

通过提供MicrometerMetricsCaptor的子类,可以定制由集成组件创建的Meters的名称和标记。MicroMeterCustomMetricstests (opens new window)测试用例展示了如何实现这一点的一个简单示例。你还可以通过在 Builder 子类上重载build()方法来进一步自定义仪表。

从版本 5.1.13 开始,QueueChannel公开了用于队列大小和剩余容量的千分尺:

  • name: spring.integration.channel.queue.size

  • tag: type:channel

  • tag: name:<componentName>

  • description: The size of the queue channel

and

  • name: spring.integration.channel.queue.remaining.capacity

  • tag: type:channel

  • tag: name:<componentName>

  • description: The remaining capacity of the queue channel

# 禁用仪表

使用遗留指标(现已删除),你可以指定哪些集成组件将收集度量。默认情况下,所有仪表都是在首次使用时注册的。现在,使用 Micrometer,可以将MeterFilters 添加到MeterRegistry中,以防止部分或全部被注册。你可以通过提供的任何属性(nametag等)过滤掉(拒绝)表。有关更多信息,请参见千分尺文档中的仪表过滤器 (opens new window)

例如,给出:

@Bean
public QueueChannel noMeters() {
    return new QueueChannel(10);
}

你可以通过以下方式抑制仅此频道的仪表注册:

registry.config().meterFilter(MeterFilter.deny(id ->
        "channel".equals(id.getTag("type")) &&
        "noMeters".equals(id.getTag("name"))));

# Spring 集成 JMX 支持

另见JMX 支持

# 消息历史记录

消息传递体系结构的主要好处是松耦合,这样参与的组件就不会对彼此保持任何意识。仅这一点就使应用程序变得非常灵活,允许你在不影响流的其余部分的情况下更改组件、更改消息传递路径、更改消息消费风格(轮询与事件驱动),等等。然而,当情况出现问题时,这种低调的建筑风格可能会变得很困难。在调试时,你可能需要尽可能多的有关消息的信息(消息的来源、经过的通道和其他详细信息)。

消息历史是一种模式,它可以帮助你选择保持对消息路径的某种级别的了解,用于调试目的或维护审计跟踪。 Spring 集成提供了一种简单的方式来配置消息流,以维护消息历史记录,方法是在消息中添加一个头,并在每次消息通过被跟踪的组件时更新该头。

# 消息历史配置

要启用消息历史记录,只需要在配置中定义message-history元素(或@EnableMessageHistory),如以下示例所示:

@Configuration
@EnableIntegration
@EnableMessageHistory
<int:message-history/>

现在,每个已命名的组件(定义了“ID”的组件)都会被跟踪。该框架在你的消息中设置“历史”头。其值 aList<Properties>

考虑以下配置示例:

@MessagingGateway(defaultRequestChannel = "bridgeInChannel")
public interface SampleGateway {
   ...
}

@Bean
@Transformer(inputChannel = "enricherChannel", outputChannel="filterChannel")
HeaderEnricher sampleEnricher() {
    HeaderEnricher enricher =
           new HeaderEnricher(Collections.singletonMap("baz", new StaticHeaderValueMessageProcessor("baz")));
    return enricher;
}
<int:gateway id="sampleGateway"
    service-interface="org.springframework.integration.history.sample.SampleGateway"
    default-request-channel="bridgeInChannel"/>

<int:header-enricher id="sampleEnricher" input-channel="enricherChannel" output-channel="filterChannel">
    <int:header name="baz" value="baz"/>
</int:header-enricher>

前面的配置生成一个简单的消息历史结构,其输出类似于以下内容:

[{name=sampleGateway, type=gateway, timestamp=1283281668091},
 {name=sampleEnricher, type=header-enricher, timestamp=1283281668094}]

要访问消息历史记录,只需访问MessageHistory头。下面的示例展示了如何做到这一点:

Iterator<Properties> historyIterator =
    message.getHeaders().get(MessageHistory.HEADER_NAME, MessageHistory.class).iterator();
assertTrue(historyIterator.hasNext());
Properties gatewayHistory = historyIterator.next();
assertEquals("sampleGateway", gatewayHistory.get("name"));
assertTrue(historyIterator.hasNext());
Properties chainHistory = historyIterator.next();
assertEquals("sampleChain", chainHistory.get("name"));

你可能不想跟踪所有的组件。要根据组件的名称将历史限制为某些组件,可以提供tracked-components属性,并指定一个以逗号分隔的组件名称和模式列表,该列表与要跟踪的组件相匹配。下面的示例展示了如何做到这一点:

@Configuration
@EnableIntegration
@EnableMessageHistory("*Gateway", "sample*", "aName")
<int:message-history tracked-components="*Gateway, sample*, aName"/>

在前面的示例中,仅对以“gateway”结尾、以“sample”开头或与名称“aname”完全匹配的组件维护消息历史记录。

此外,MessageHistoryConfigurer Bean 现在被IntegrationMBeanExporter公开为 JMX MBean(参见MBean 出口商),允许你在运行时更改模式。但是,请注意,为了更改模式,必须停止 Bean(关闭消息历史记录)。这个特性对于临时打开历史记录来分析系统可能是有用的。MBean 的对象名是<domain>:name=messageHistoryConfigurer,type=MessageHistoryConfigurer

只有一个@EnableMessageHistory(或<message-history/>)必须在应用程序上下文中声明为组件跟踪配置的单个源。
不要为MessageHistoryConfigurer使用通用的 Bean 定义。
根据定义,消息历史记录头是不可变的(不能重写历史记录),因此,在编写消息历史记录值时,组件要么创建新消息(当组件是源消息时),要么从请求消息中复制历史记录,修改它并在回复消息上设置新的列表。
在这两种情况下,即使消息本身跨越了线程边界,也可以追加这些值。
这意味着历史值可以大大简化异步消息流中的调试。

# 消息存储

*Enterprise 整合模式 * (opens new window)书标识了几种具有缓冲消息能力的模式。例如,聚合器缓冲消息直到可以释放消息,而QueueChannel缓冲消息直到消费者明确地从该通道接收这些消息。由于消息流中的任何一点都可能发生故障,缓冲消息的 EIP 组件还引入了消息可能丢失的点。

为了减少丢失消息的风险,EIP 定义了消息存储 (opens new window)模式,该模式允许 EIP 组件存储消息,通常是在某种类型的持久性存储(例如 RDBMS)中。

Spring 集成通过以下方式提供对消息存储模式的支持:

  • 定义org.springframework.integration.store.MessageStore策略接口

  • 提供此接口的几种实现方式

  • 在所有具有缓冲消息功能的组件上公开message-store属性,以便你可以插入实现MessageStore接口的任何实例。

有关如何配置特定消息存储实现以及如何将MessageStore实现注入特定缓冲组件的详细信息在整个手册中进行了描述(请参阅特定组件,例如QueuechannelAggregatorDelayer等)。以下两个示例展示了如何为QueueChannel和聚合器向消息存储区添加引用:

例1.Queuechannel

<int:channel id="myQueueChannel">
    <int:queue message-store="refToMessageStore"/>
<int:channel>

例2.聚合器

<int:aggregator … message-store="refToMessageStore"/>

默认情况下,消息通过使用o.s.i.store.SimpleMessageStore存储在内存中,这是MessageStore的一种实现。对于开发环境或简单的低容量环境来说,这可能是很好的,在这些环境中,潜在的非持久性消息丢失不是一个问题。然而,典型的生产应用程序需要一个更健壮的选项,不仅要减轻消息丢失的风险,还要避免潜在的内存不足错误。因此,我们还为各种数据存储提供MessageStore实现。以下是受支持的实现的完整列表:

但是,在使用MessageStore的持久实现时要注意一些限制。

消息数据(有效载荷和报头)通过使用不同的序列化策略进行序列化和反序列化,这取决于MessageStore的实现方式。
例如,当使用JdbcMessageStore时,默认情况下,只有Serializable数据是持久的。
在这种情况下,在进行序列化之前,要删除不可序列化的标头。
此外,要注意传输适配器(例如 FTP、HTTP、JMS 和其他)注入的特定于协议的标头。
例如,<http:inbound-channel-adapter/>将 HTTP 标头映射到消息标头,其中之一是一个ArrayList的不可序列化org.springframework.http.MediaType实例。你可以将你自己的SerializerDeserializer策略接口的实现注入到一些MessageStore实现中(例如JdbcMessageStore),以改变序列化和反序列化的行为。

特别注意表示某些类型数据的头。
例如,如果其中一个头包含某个 Spring Bean 的实例,那么在反序列化时,你可能会得到另一个 Bean 的实例,这将直接影响框架创建的一些隐式头(例如REPLY_CHANNELERROR_CHANNEL)。,
目前,它们不能序列化,但是,即使它们是,反序列化的通道也不会表示预期的实例。

从 Spring Integration3.0 开始,你可以使用配置为在用HeaderChannelRegistry注册通道后用名称替换这些头的 header 来解决此问题,

同样,考虑一下,当你按照以下方式配置消息流时会发生什么:网关队列通道(由持久性消息存储支持)服务激活器,
该网关创建了一个临时回复通道,当服务激活器的 poller 从队列中读取消息时,该通道会丢失。,再次,<gtr=“217”/,你可以使用 header enricher 用String表示替换 header。

有关更多信息,请参见页眉 Enricher

Spring Integration4.0 引入了两个新的接口:

  • ChannelMessageStore:实现针对QueueChannel实例的特定操作

  • PriorityCapableChannelMessageStore:标记用于MessageStore实例的PriorityChannel实现,并为持久消息提供优先顺序。

真正的行为取决于执行情况。该框架提供了以下实现方式,它们可以用作MessageStorePriorityChannel的持久性MessageStore:

注意SimpleMessageStore

从版本 4.1 开始,在调用SimpleMessageStore时,SimpleMessageStore不再复制消息组。对于大型消息组,
,这是一个重要的性能问题。
4.0.1 引入了一个布尔copyOnGet属性,该属性允许你控制此行为,
当聚合器内部使用时,将此属性设置为false以提高性能。
默认情况下,它现在是false

在组件之外访问组存储的用户因为聚合器现在获得了对聚合器正在使用的组的直接引用,而不是一个副本。
聚合器之外的组的操作可能会导致不可预测的结果。

由于这个原因,你不应该执行这样的操作,或者将copyOnGet属性设置为true

# 使用MessageGroupFactory

从版本 4.3 开始,一些MessageGroupStore实现可以被注入一个自定义MessageGroupFactory策略来创建和定制MessageGroup实例,该实例由MessageGroupStore使用。这默认为SimpleMessageGroupFactory,它基于GroupType.HASH_SETLinkedHashSet)内部集合生成SimpleMessageGroup实例。其他可能的选项是SYNCHRONISED_SETBLOCKING_QUEUE,其中最后一个选项可以用来恢复先前的SimpleMessageGroup行为。而且PERSISTENT选项也是可用的。有关更多信息,请参见下一节。从版本 5.0.1 开始,当组中消息的顺序和唯一性无关紧要时,LIST选项也可用。

# 持久MessageGroupStore和 lazy-load

从版本 4.3 开始,所有持久的MessageGroupStore实例都以延迟加载的方式从存储中检索MessageGroup实例及其messages实例。在大多数情况下,对于相关MessageHandler实例是有用的(参见Aggregator重测序器),当它将增加开销以从存储中加载整个MessageGroup上的每个相关操作时。

你可以使用AbstractMessageGroupStore.setLazyLoadMessageGroups(false)选项从配置中关闭惰性负载行为。

我们对 MongoDBMessageStoreMongoDB 消息存储)和<aggregator>Aggregator)上的 lazy-load 进行的性能测试使用了一个自定义release-strategy,类似于以下内容:

<int:aggregator input-channel="inputChannel"
                output-channel="outputChannel"
                message-store="mongoStore"
                release-strategy-expression="size() == 1000"/>

它为 1000 条简单消息生成类似于以下结果的结果:

...
StopWatch 'Lazy-Load Performance': running time (millis) = 38918
-----------------------------------------
ms     %     Task name
-----------------------------------------
02652  007%  Lazy-Load
36266  093%  Eager
...

然而,从版本 5.5 开始,所有持久的MessageGroupStore实现都提供了基于目标数据库流 API 的streamMessagesForGroup(Object groupId)契约。当存储中的组非常大时,这将提高资源利用率。在框架内部,这个新的 API 在Delayer中使用(例如),当它重新安排启动时的持久化消息时。返回的Stream<Message<?>>必须在处理结束时关闭,例如通过try-with-resources自动关闭。每当使用PersistentMessageGroup时,将其streamMessages()委托给MessageGroupStore.streamMessagesForGroup()

# 消息组条件

从版本 5.5 开始,MessageGroup抽象提供了condition字符串选项。此选项的值可以是任何可以在稍后进行解析的内容,以便为组做出决定。例如,来自相关消息处理程序ReleaseStrategy可能会从组中查询此属性,而不是迭代组中的所有消息。MessageGroupStore公开了setGroupCondition(Object groupId, String condition)API。为此,在AbstractCorrelatingMessageHandler中添加了setGroupConditionSupplier(BiFunction<Message<?>, String, String>)选项。此函数是在将每个消息添加到该组以及该组的现有条件之后,针对每个消息进行求值的。该实现可以决定返回一个新的值、现有的值,或者将目标条件重置为nullcondition的值可以是 JSON、SPEL 表达式、数字或任何可以序列化为字符串并在之后进行解析的内容。例如,来自文件聚合器组件的FileMarkerReleaseStrategy将一个条件从FileHeaders.LINE_COUNT消息的FileSplitter.FileMarker.Mark.END头中填充到一个组中,并从其canRelease()中与该组中的值进行比较,并与之进行协商。这样,它就不会迭代组中的所有消息来查找带有FileHeaders.LINE_COUNT头的FileSplitter.FileMarker.Mark.END消息。它还允许结束标记在所有其他记录之前到达聚合器;例如,在多线程环境中处理文件时。

此外,为了方便配置,引入了GroupConditionProvider契约。AbstractCorrelatingMessageHandler检查所提供的ReleaseStrategy是否实现了该接口,并提取了用于组条件评估逻辑的conditionSupplier

# 元数据存储

许多外部系统、服务或资源不是事务性的(Twitter、RSS、文件系统等),并且没有任何能力将数据标记为已读。此外,有时,你可能需要在一些集成解决方案中实现 Enterprise 集成模式幂等接收机 (opens new window)。为了实现这一目标并在下一次与外部系统交互之前存储端点的一些先前状态或处理下一次消息, Spring 集成提供了元数据存储组件作为org.springframework.integration.metadata.MetadataStore接口的一种实现方式,具有一般的键值契约。

元数据存储旨在存储各种类型的通用元数据(例如,已处理的最后一个提要条目的发布日期),以帮助提要适配器等组件处理重复数据。如果组件没有直接提供对MetadataStore的引用,则用于定位元数据存储的算法如下:首先,在应用程序上下文中查找具有metadataStoreID 的 Bean。如果找到了,就使用它。否则,创建一个SimpleMetadataStore的新实例,这是一个内存中的实现,它只在当前运行的应用程序上下文的生命周期内持久化元数据。这意味着,在重新启动时,你可能会以重复的条目结束。

如果需要在应用程序上下文重新启动之间持久化元数据,则框架提供以下持久化MetadataStores:

PropertiesPersistingMetadataStore由一个属性文件和一个[PropertiesPersister](https://DOCS. Spring.io/ Spring/DOCS/current/javadoc-api/org/springframework/util/propertiespersister.html)支持。

默认情况下,它仅在应用程序上下文正常关闭时保持状态。它实现了Flushable,这样你就可以通过调用flush()随意地持久化状态。下面的示例展示了如何使用 XML 配置“PropertiesPersistingMetaDataStore”:

<bean id="metadataStore"
    class="org.springframework.integration.metadata.PropertiesPersistingMetadataStore"/>

或者,你可以提供你自己的MetadataStore接口的实现(例如,JdbcMetadataStore),并将其配置为应用程序上下文中的 Bean。

从版本 4.0 开始,SimpleMetadataStorePropertiesPersistingMetadataStore,和RedisMetadataStore实现ConcurrentMetadataStore。它们提供了原子更新,并且可以跨多个组件或应用程序实例使用。

# 幂等接收器和元数据存储

当需要过滤已处理的传入消息时,元数据存储对于实现 EIP幂等接收机 (opens new window)模式非常有用,并且可以丢弃它或在丢弃时执行其他逻辑。下面的配置展示了如何这样做的示例:

<int:filter input-channel="serviceChannel"
			output-channel="idempotentServiceChannel"
			discard-channel="discardChannel"
			expression="@metadataStore.get(headers.businessKey) == null"/>

<int:publish-subscribe-channel id="idempotentServiceChannel"/>

<int:outbound-channel-adapter channel="idempotentServiceChannel"
                              expression="@metadataStore.put(headers.businessKey, '')"/>

<int:service-activator input-channel="idempotentServiceChannel" ref="service"/>

幂等条目的value可能是一个到期日期,在此日期之后,某个预定的收割者应该将该条目从元数据存储中删除。

另见幂等接收机 Enterprise 集成模式

# MetadataStoreListener

一些元数据存储(目前只有 ZooKeeper)支持注册侦听器,以便在项目更改时接收事件,如下例所示:

public interface MetadataStoreListener {

	void onAdd(String key, String value);

	void onRemove(String key, String oldValue);

	void onUpdate(String key, String newValue);
}

有关更多信息,请参见Javadoc (opens new window)。如果你只对事件的一个子集感兴趣,那么MetadataStoreListenerAdapter可以被子类。

# 控制总线

正如*Enterprise 整合模式 * (opens new window)一书中所描述的,控制总线背后的思想是,可以使用与“应用程序级”消息传递相同的消息传递系统来监视和管理框架内的组件。在 Spring 集成中,我们构建在上面描述的适配器的基础上,以便你可以发送消息作为调用公开操作的一种方式。

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

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

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

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

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

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

使用 Java 注释,你可以将控制总线配置如下:

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

类似地,你可以按以下方式配置 Java DSL 流定义:

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

如果你更喜欢使用带有自动DirectChannel创建的 lambdas,则可以按以下方式创建控制总线:

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

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

# 有序关机

如“MBean 出口商”中所述,MBean Exporter 提供了一个名为stopActiveComponents的 JMX 操作,该操作用于以有序的方式停止应用程序。该操作有一个Long参数。该参数指示操作等待多长时间(以毫秒为单位)以允许飞行中的消息完成。该行动的工作方式如下:

  1. 在所有实现OrderlyShutdownCapable的 bean 上调用beforeShutdown()

    这样做可以让这些组件为关闭做好准备。实现这个接口的组件的例子,以及它们对这个调用所做的工作,包括 JMS 和 AMQP 消息驱动的适配器,这些适配器停止它们的侦听器容器,TCP 服务器连接工厂停止接受新连接(同时保持现有连接打开),TCP 入站端点丢弃(记录)接收到的任何新消息,和 HTTP 入站端点,对于任何新请求返回503 - Service Unavailable

  2. 停止任何活动通道,如 JMS 或 AMQP 支持的通道。

  3. 停止所有MessageSource实例。

  4. 停止所有入站MessageProducers(不是OrderlyShutdownCapable)。

  5. 等待剩余的任何时间,如传递给操作的Long参数的值所定义的。

    这样做可以让任何飞行中的信息完成它们的旅程。因此,在调用此操作时选择一个适当的超时是很重要的。

  6. 在所有OrderlyShutdownCapable组件上调用afterShutdown()

    这样做可以让这些组件执行最后的关闭任务(例如,关闭所有打开的套接字)。

正如有序停机管理运行中所讨论的,可以通过使用 JMX 调用此操作。如果希望以编程方式调用该方法,则需要注入或以其他方式获得对IntegrationMBeanExporter的引用。如果在<int-jmx:mbean-export/>定义中没有提供id属性,则 Bean 具有生成的名称。如果同一 JVM(MBeanServer)中存在多个 Spring 集成上下文,则该名称包含一个随机组件,以避免ObjectName冲突。

出于这个原因,如果你希望以编程方式调用该方法,我们建议你为 exporter 提供一个id属性,以便你可以在应用程序上下文中轻松地访问它。

最后,可以使用<control-bus>元素调用该操作。有关详细信息,请参见monitoring Spring Integration sample application (opens new window)

前面描述的算法在版本 4.1 中得到了改进。
以前,所有的任务执行器和调度程序都被停止。
这可能导致QueueChannel实例中的中间流消息保持不变。
现在关闭将使 pollers 继续运行,以使这些消息被耗尽并得到处理。

# 积分图

从版本 4.3 开始, Spring 集成提供了对应用程序运行时对象模型的访问,其中可以选择包括组件指标。它以图形的形式公开,可用于可视化集成应用程序的当前状态。o.s.i.support.management.graph包包含收集、构建和呈现 Spring 集成组件的运行时状态作为单个树状Graph对象所需的所有类。应该将IntegrationGraphServer声明为用于构建、检索和刷新Graph对象的 Bean。结果Graph对象可以序列化为任何格式,尽管 JSON 在客户端解析和表示时非常灵活和方便。 Spring 只包含缺省组件的集成应用程序将公开如下图:

{
  "contentDescriptor" : {
    "providerVersion" : "5.5.9",
    "providerFormatVersion" : 1.2,
    "provider" : "spring-integration",
    "name" : "myAppName:1.0"
  },
  "nodes" : [ {
    "nodeId" : 1,
    "componentType" : "null-channel",
    "integrationPatternType" : "null_channel",
    "integrationPatternCategory" : "messaging_channel",
    "properties" : { },
    "sendTimers" : {
      "successes" : {
        "count" : 1,
        "mean" : 0.0,
        "max" : 0.0
      },
      "failures" : {
        "count" : 0,
        "mean" : 0.0,
        "max" : 0.0
      }
    },
    "receiveCounters" : {
      "successes" : 0,
      "failures" : 0
    },
    "name" : "nullChannel"
  }, {
    "nodeId" : 2,
    "componentType" : "publish-subscribe-channel",
    "integrationPatternType" : "publish_subscribe_channel",
    "integrationPatternCategory" : "messaging_channel",
    "properties" : { },
    "sendTimers" : {
      "successes" : {
        "count" : 1,
        "mean" : 7.807002,
        "max" : 7.807002
      },
      "failures" : {
        "count" : 0,
        "mean" : 0.0,
        "max" : 0.0
      }
    },
    "name" : "errorChannel"
  }, {
    "nodeId" : 3,
    "componentType" : "logging-channel-adapter",
    "integrationPatternType" : "outbound_channel_adapter",
    "integrationPatternCategory" : "messaging_endpoint",
    "properties" : { },
    "output" : null,
    "input" : "errorChannel",
    "sendTimers" : {
      "successes" : {
        "count" : 1,
        "mean" : 6.742722,
        "max" : 6.742722
      },
      "failures" : {
        "count" : 0,
        "mean" : 0.0,
        "max" : 0.0
      }
    },
    "name" : "errorLogger"
  } ],
  "links" : [ {
    "from" : 2,
    "to" : 3,
    "type" : "input"
  } ]
}
版本 5.2 不赞成使用旧版度量标准,而使用度量管理.
所讨论的千分尺。

在前面的示例中,图由三个顶级元素组成。

contentDescriptor图元素包含有关提供数据的应用程序的一般信息。可以在IntegrationGraphServer Bean 或spring.application.name应用程序上下文环境属性中定制name。框架提供了其他属性,让你将类似的模型与其他来源区分开来。

links图元素表示来自nodes图元素的节点之间的连接,因此表示源 Spring 集成应用程序中的集成组件之间的连接。例如,从一个MessageChannel到一个EventDrivenConsumer,加上一些MessageHandler,或者从一个AbstractReplyProducingMessageHandler到一个MessageChannel。为了方便起见并让你确定链接的目的,该模型包含type属性。可能的类型有:

  • input:标识从MessageChannel到端点的方向,inputChannel,或requestChannel属性

  • output:从MessageHandlerMessageProducer,或SourcePollingChannelAdapterMessageChannel的方向,通过outputChannelreplyChannel属性

  • error:从MessageHandleronPollingConsumerMessageProducerorSourcePollingChannelAdapterMessageChannel通过errorChannel属性;

  • discard:通过errorChannel属性从DiscardingMessageHandler(如MessageFilter)到MessageChannel

  • route:从AbstractMappingMessageRouter(如HeaderValueRouter)到MessageChannel。类似于output,但在运行时确定。可以是已配置的通道映射或动态解析的通道.为此,路由器通常只保留多达 100 个动态路由,但是你可以通过设置dynamicChannelLimit属性来修改该值。

来自此元素的信息可以由可视化工具用于呈现来自nodes图元素的节点之间的连接,其中fromto数字表示来自链接节点的nodeId属性的值。例如,link元素可用于确定目标节点上的适当port

下面的“文本图像”显示了类型之间的关系:

              +---(discard)
              |
         +----o----+
         |         |
         |         |
         |         |
(input)--o         o---(output)
         |         |
         |         |
         |         |
         +----o----+
              |
              +---(error)

nodes图元素可能是最有趣的,因为它的元素不仅包含运行时组件及其componentType实例和name值,而且还可以选择性地包含组件公开的度量。节点元素包含各种属性,这些属性通常是不言自明的。例如,基于表达式的组件包括expression属性,该属性包含组件的主表达式字符串。要启用度量,可以将@EnableIntegrationManagement添加到@Configuration类中,或者将<int:management/>元素添加到 XML 配置中。有关完整信息,请参见度量和管理

nodeId表示一个唯一的增量标识符,可以让你区分一个组件和另一个组件。在links元素中,它也用于表示此组件与其他组件(如果有的话)的关系(连接)。inputoutput属性用于inputChanneloutputChannel属性的AbstractEndpointMessageHandlerSourcePollingChannelAdapter,或MessageProducerSupport。有关更多信息,请参见下一节。

从版本 5.1 开始,IntegrationGraphServer对于特定的NamedComponent,在IntegrationNode上的附加属性的总体接受Function<NamedComponent, Map<String, Object>> additionalPropertiesCallback。例如,你可以将SmartLifecycle``autoStartuprunning属性公开到目标图形中:

server.setAdditionalPropertiesCallback(namedComponent -> {
            Map<String, Object> properties = null;
            if (namedComponent instanceof SmartLifecycle) {
                SmartLifecycle smartLifecycle = (SmartLifecycle) namedComponent;
                properties = new HashMap<>();
                properties.put("auto-startup", smartLifecycle.isAutoStartup());
                properties.put("running", smartLifecycle.isRunning());
            }
            return properties;
        });

# 图运行时模型

Spring 集成组件具有不同级别的复杂性。例如,任何被调查者MessageSource还具有一个SourcePollingChannelAdapter和一个MessageChannel,从源数据定期向其发送消息。其他组件可能是中间件请求-回复组件(例如JmsOutboundGateway),其使用AbstractEndpoint来订阅(或轮询)用于消息的requestChannelinput),以及用于生成向下游发送的回复消息的replyChanneloutput)。同时,任何MessageProducerSupport实现(例如ApplicationEventListeningMessageProducer)都会封装一些源协议侦听逻辑并将消息发送到outputChannel

在图中, Spring 积分组件通过使用IntegrationNode类层次结构来表示,你可以在o.s.i.support.management.graph包中找到它。例如,对于AggregatingMessageHandler可以使用ErrorCapableDiscardingMessageHandlerNode(因为它有一个discardChannel选项),并且在使用PollableChannel时可以产生错误。另一个例子是CompositeMessageHandlerNode—当通过使用EventDrivenConsumer订阅SubscribableChannel时,用于MessageHandlerChain

@MessagingGateway(参见消息传递网关)为其每个方法提供节点,其中name属性基于网关的 Bean 名称和简短的方法签名。
考虑以下网关示例:
@MessagingGateway(defaultRequestChannel = "four")
public interface Gate {

	void foo(String foo);

	void foo(Integer foo);

	void bar(String bar);

}

前面的网关产生的节点类似于以下内容:

{
  "nodeId" : 10,
  "name" : "gate.bar(class java.lang.String)",
  "stats" : null,
  "componentType" : "gateway",
  "integrationPatternType" : "gateway",
  "integrationPatternCategory" : "messaging_endpoint",
  "output" : "four",
  "errors" : null
},
{
  "nodeId" : 11,
  "name" : "gate.foo(class java.lang.String)",
  "stats" : null,
  "componentType" : "gateway",
  "integrationPatternType" : "gateway",
  "integrationPatternCategory" : "messaging_endpoint",
  "output" : "four",
  "errors" : null
},
{
  "nodeId" : 12,
  "name" : "gate.foo(class java.lang.Integer)",
  "stats" : null,
  "componentType" : "gateway",
  "integrationPatternType" : "gateway",
  "integrationPatternCategory" : "messaging_endpoint",
  "output" : "four",
  "errors" : null
}

你可以使用这个IntegrationNode层次结构在客户端解析图形模型,以及理解一般的 Spring 集成运行时行为。有关更多信息,请参见编程技巧和技巧

版本 5.3 引入了一个IntegrationPattern抽象和所有开箱即用的组件,它们代表一个 Enterprise 集成模式,实现了这个抽象,并提供了一个IntegrationPatternTypeenum 值。对于目标应用程序中的某些分类逻辑来说,这些信息可能是有用的,或者,当暴露在图形节点中时,UI 可以使用这些信息来确定如何绘制组件。

# 积分图控制器

如果你的应用程序是基于 Web 的(或构建在带有嵌入式 Web 容器的 Spring 启动之上),并且 Spring 集成 HTTP 或 WebFlux 模块(分别参见和)存在于 Classpath 上,你可以使用IntegrationGraphControllerIntegrationGraphServer功能公开为 REST 服务。为此,@EnableIntegrationGraphController@Configuration类注释和<int-http:graph-controller/>XML 元素在 HTTP 模块中可用。与@EnableWebMvc注释(或用于 XML 定义的<mvc:annotation-driven/>)一起,此配置注册了IntegrationGraphController``@RestController,其中其@RequestMapping.path可以在@EnableIntegrationGraphController注释或<int-http:graph-controller/>元素上进行配置。默认路径是/integration

IntegrationGraphController``@RestController提供以下服务:

  • @GetMapping(name = "getGraph"):检索自上次IntegrationGraphServer刷新后 Spring 集成组件的状态。将o.s.i.support.management.graph.Graph作为 REST 服务的@ResponseBody返回。

  • @GetMapping(path = "/refresh", name = "refreshGraph"):为实际运行时状态刷新当前Graph,并将其作为 REST 响应返回。没有必要刷新图表以获取度量。当图形被检索时,它们是实时提供的。如果自上次检索图表以来应用程序上下文已被修改,则可以调用刷新。在这种情况下,这个图是完全重建的。

你可以使用 Spring Security 和 Spring MVC 项目提供的标准配置选项和组件,为IntegrationGraphController设置安全性和跨源限制。下面的示例实现了这些目标:

<mvc:annotation-driven />

<mvc:cors>
	<mvc:mapping path="/myIntegration/**"
				 allowed-origins="http://localhost:9090"
				 allowed-methods="GET" />
</mvc:cors>

<security:http>
    <security:intercept-url pattern="/myIntegration/**" access="ROLE_ADMIN" />
</security:http>

<int-http:graph-controller path="/myIntegration" />

下面的示例展示了如何对 Java 配置执行相同的操作:

@Configuration
@EnableWebMvc // or @EnableWebFlux
@EnableWebSecurity // or @EnableWebFluxSecurity
@EnableIntegration
@EnableIntegrationGraphController(path = "/testIntegration", allowedOrigins="http://localhost:9090")
public class IntegrationConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
	    http
            .authorizeRequests()
               .antMatchers("/testIntegration/**").hasRole("ADMIN")
            // ...
            .formLogin();
    }

    //...

}

注意,为了方便起见,@EnableIntegrationGraphController注释提供了一个allowedOrigins属性。这提供了GETpath的访问。为了更复杂,你可以使用标准的 Spring MVC 机制来配置 CORS 映射。