# 系统管理
# 系统管理
# 指标和管理
本节描述如何捕获 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,将MeterRegistry
bean 中的一个添加到应用程序上下文中。
对于每个MessageH和ler
和MessageChannel
,计时器被注册。对于每个MessageSource
,注册一个计数器。
这仅适用于扩展AbstractMessageHandler
、AbstractMessageChannel
和AbstractMessageSource
的对象(大多数框架组件都是这种情况)。
用于在消息通道上进行发送操作的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,可以将MeterFilter
s 添加到MeterRegistry
中,以防止部分或全部被注册。你可以通过提供的任何属性(name
、tag
等)过滤掉(拒绝)表。有关更多信息,请参见千分尺文档中的仪表过滤器 (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
实现注入特定缓冲组件的详细信息在整个手册中进行了描述(请参阅特定组件,例如Queuechannel,Aggregator,Delayer等)。以下两个示例展示了如何为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
实现。以下是受支持的实现的完整列表:
JDBC 消息存储:使用 RDBMS 存储消息
Redis 消息存储:使用 Redis 键/值数据存储来存储消息
MongoDB 消息存储:使用 MongoDB 文档存储来存储消息
Gemfire 消息存储:使用 Gemfire 分布式缓存存储消息
但是,在使用MessageStore 的持久实现时要注意一些限制。消息数据(有效载荷和报头)通过使用不同的序列化策略进行序列化和反序列化,这取决于 MessageStore 的实现方式。例如,当使用 JdbcMessageStore 时,默认情况下,只有Serializable 数据是持久的。在这种情况下,在进行序列化之前,要删除不可序列化的标头。 此外,要注意传输适配器(例如 FTP、HTTP、JMS 和其他)注入的特定于协议的标头。 例如, <http:inbound-channel-adapter/> 将 HTTP 标头映射到消息标头,其中之一是一个ArrayList 的不可序列化org.springframework.http.MediaType 实例。你可以将你自己的Serializer 和Deserializer 策略接口的实现注入到一些MessageStore 实现中(例如JdbcMessageStore ),以改变序列化和反序列化的行为。特别注意表示某些类型数据的头。 例如,如果其中一个头包含某个 Spring Bean 的实例,那么在反序列化时,你可能会得到另一个 Bean 的实例,这将直接影响框架创建的一些隐式头(例如 REPLY_CHANNEL 或ERROR_CHANNEL )。,目前,它们不能序列化,但是,即使它们是,反序列化的通道也不会表示预期的实例。 从 Spring Integration3.0 开始,你可以使用配置为在用 HeaderChannelRegistry 注册通道后用名称替换这些头的 header 来解决此问题,同样,考虑一下,当你按照以下方式配置消息流时会发生什么:网关队列通道(由持久性消息存储支持)服务激活器, 该网关创建了一个临时回复通道,当服务激活器的 poller 从队列中读取消息时,该通道会丢失。,再次,<gtr=“217”/,你可以使用 header enricher 用 String 表示替换 header。有关更多信息,请参见页眉 Enricher。 |
---|
Spring Integration4.0 引入了两个新的接口:
ChannelMessageStore
:实现针对QueueChannel
实例的特定操作PriorityCapableChannelMessageStore
:标记用于MessageStore
实例的PriorityChannel
实现,并为持久消息提供优先顺序。
真正的行为取决于执行情况。该框架提供了以下实现方式,它们可以用作MessageStore
和PriorityChannel
的持久性MessageStore
:
注意SimpleMessageStore 从版本 4.1 开始,在调用 SimpleMessageStore 时,SimpleMessageStore 不再复制消息组。对于大型消息组,,这是一个重要的性能问题。 4.0.1 引入了一个布尔 copyOnGet 属性,该属性允许你控制此行为,当聚合器内部使用时,将此属性设置为 false 以提高性能。默认情况下,它现在是 false 。在组件之外访问组存储的用户因为聚合器现在获得了对聚合器正在使用的组的直接引用,而不是一个副本。 聚合器之外的组的操作可能会导致不可预测的结果。 由于这个原因,你不应该执行这样的操作,或者将 copyOnGet 属性设置为true 。 |
---|
# 使用MessageGroupFactory
从版本 4.3 开始,一些MessageGroupStore
实现可以被注入一个自定义MessageGroupFactory
策略来创建和定制MessageGroup
实例,该实例由MessageGroupStore
使用。这默认为SimpleMessageGroupFactory
,它基于GroupType.HASH_SET
(LinkedHashSet
)内部集合生成SimpleMessageGroup
实例。其他可能的选项是SYNCHRONISED_SET
和BLOCKING_QUEUE
,其中最后一个选项可以用来恢复先前的SimpleMessageGroup
行为。而且PERSISTENT
选项也是可用的。有关更多信息,请参见下一节。从版本 5.0.1 开始,当组中消息的顺序和唯一性无关紧要时,LIST
选项也可用。
# 持久MessageGroupStore
和 lazy-load
从版本 4.3 开始,所有持久的MessageGroupStore
实例都以延迟加载的方式从存储中检索MessageGroup
实例及其messages
实例。在大多数情况下,对于相关MessageHandler
实例是有用的(参见Aggregator和重测序器),当它将增加开销以从存储中加载整个MessageGroup
上的每个相关操作时。
你可以使用AbstractMessageGroupStore.setLazyLoadMessageGroups(false)
选项从配置中关闭惰性负载行为。
我们对 MongoDBMessageStore
(MongoDB 消息存储)和<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>)
选项。此函数是在将每个消息添加到该组以及该组的现有条件之后,针对每个消息进行求值的。该实现可以决定返回一个新的值、现有的值,或者将目标条件重置为null
。condition
的值可以是 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
的引用,则用于定位元数据存储的算法如下:首先,在应用程序上下文中查找具有metadataStore
ID 的 Bean。如果找到了,就使用它。否则,创建一个SimpleMetadataStore
的新实例,这是一个内存中的实现,它只在当前运行的应用程序上下文的生命周期内持久化元数据。这意味着,在重新启动时,你可能会以重复的条目结束。
如果需要在应用程序上下文重新启动之间持久化元数据,则框架提供以下持久化MetadataStores
:
PropertiesPersistingMetadataStore
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 开始,SimpleMetadataStore
,PropertiesPersistingMetadataStore
,和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
可能是一个到期日期,在此日期之后,某个预定的收割者应该将该条目从元数据存储中删除。
# 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 的TaskExecutor
和TaskScheduler
实现的几种方法。确保你自己的方法对控制总线可用的最简单的方法是使用@ManagedAttribute
或@ManagedOperation
注释。由于这些注释也用于向 JMX MBean 注册中心公开方法,因此它们提供了一个方便的副产品:通常,你希望向控制总线公开的相同类型的操作在通过 JMX 公开时是合理的。应用程序上下文中任何特定实例的解析都是用典型的 SPEL 语法实现的。要做到这一点,请为 Bean 名称提供带有 bean 的 SPEL 前缀(@
)。例如,要在 Spring Bean 上执行方法,客户端可以向操作通道发送如下消息:
Message operation = MessageBuilder.withPayload("@myServiceBean.shutdown()").build();
operationChannel.send(operation)
表达式的上下文的根是Message
本身,因此你还可以访问payload
和headers
作为表达式中的变量。这与 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
参数。该参数指示操作等待多长时间(以毫秒为单位)以允许飞行中的消息完成。该行动的工作方式如下:
在所有实现
OrderlyShutdownCapable
的 bean 上调用beforeShutdown()
。这样做可以让这些组件为关闭做好准备。实现这个接口的组件的例子,以及它们对这个调用所做的工作,包括 JMS 和 AMQP 消息驱动的适配器,这些适配器停止它们的侦听器容器,TCP 服务器连接工厂停止接受新连接(同时保持现有连接打开),TCP 入站端点丢弃(记录)接收到的任何新消息,和 HTTP 入站端点,对于任何新请求返回
503 - Service Unavailable
。停止任何活动通道,如 JMS 或 AMQP 支持的通道。
停止所有
MessageSource
实例。停止所有入站
MessageProducer
s(不是OrderlyShutdownCapable
)。等待剩余的任何时间,如传递给操作的
Long
参数的值所定义的。这样做可以让任何飞行中的信息完成它们的旅程。因此,在调用此操作时选择一个适当的超时是很重要的。
在所有
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
:从MessageHandler
,MessageProducer
,或SourcePollingChannelAdapter
到MessageChannel
的方向,通过outputChannel
或replyChannel
属性error
:从MessageHandler
onPollingConsumer
或MessageProducer
orSourcePollingChannelAdapter
到MessageChannel
通过errorChannel
属性;discard
:通过errorChannel
属性从DiscardingMessageHandler
(如MessageFilter
)到MessageChannel
。route
:从AbstractMappingMessageRouter
(如HeaderValueRouter
)到MessageChannel
。类似于output
,但在运行时确定。可以是已配置的通道映射或动态解析的通道.为此,路由器通常只保留多达 100 个动态路由,但是你可以通过设置dynamicChannelLimit
属性来修改该值。
来自此元素的信息可以由可视化工具用于呈现来自nodes
图元素的节点之间的连接,其中from
和to
数字表示来自链接节点的nodeId
属性的值。例如,link
元素可用于确定目标节点上的适当port
。
下面的“文本图像”显示了类型之间的关系:
+---(discard)
|
+----o----+
| |
| |
| |
(input)--o o---(output)
| |
| |
| |
+----o----+
|
+---(error)
nodes
图元素可能是最有趣的,因为它的元素不仅包含运行时组件及其componentType
实例和name
值,而且还可以选择性地包含组件公开的度量。节点元素包含各种属性,这些属性通常是不言自明的。例如,基于表达式的组件包括expression
属性,该属性包含组件的主表达式字符串。要启用度量,可以将@EnableIntegrationManagement
添加到@Configuration
类中,或者将<int:management/>
元素添加到 XML 配置中。有关完整信息,请参见度量和管理。
nodeId
表示一个唯一的增量标识符,可以让你区分一个组件和另一个组件。在links
元素中,它也用于表示此组件与其他组件(如果有的话)的关系(连接)。input
和output
属性用于inputChannel
和outputChannel
属性的AbstractEndpoint
,MessageHandler
,SourcePollingChannelAdapter
,或MessageProducerSupport
。有关更多信息,请参见下一节。
从版本 5.1 开始,IntegrationGraphServer
对于特定的NamedComponent
,在IntegrationNode
上的附加属性的总体接受Function<NamedComponent, Map<String, Object>> additionalPropertiesCallback
。例如,你可以将SmartLifecycle``autoStartup
和running
属性公开到目标图形中:
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
来订阅(或轮询)用于消息的requestChannel
(input
),以及用于生成向下游发送的回复消息的replyChannel
(output
)。同时,任何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 集成模式,实现了这个抽象,并提供了一个IntegrationPatternType
enum 值。对于目标应用程序中的某些分类逻辑来说,这些信息可能是有用的,或者,当暴露在图形节点中时,UI 可以使用这些信息来确定如何绘制组件。
# 积分图控制器
如果你的应用程序是基于 Web 的(或构建在带有嵌入式 Web 容器的 Spring 启动之上),并且 Spring 集成 HTTP 或 WebFlux 模块(分别参见和)存在于 Classpath 上,你可以使用IntegrationGraphController
将IntegrationGraphServer
功能公开为 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
属性。这提供了GET
对path
的访问。为了更复杂,你可以使用标准的 Spring MVC 机制来配置 CORS 映射。
← Kotlin DSL 反应流支持 →