跳到主要内容
版本:7.0.2

JMX 支持

DeepSeek V3 中英对照 JMX Support

Spring Integration 提供了用于接收和发布 JMX 通知的通道适配器。

此依赖项为项目所需:

<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jmx</artifactId>
<version>7.0.2</version>
</dependency>

入站通道适配器允许轮询JMX MBean属性值,而出站通道适配器允许调用JMX MBean操作。

通知监听通道适配器

通知监听通道适配器需要一个JMX ObjectName,用于指定发布通知的MBean,该监听器将注册到此MBean。一个非常简单的配置可能如下所示:

<int-jmx:notification-listening-channel-adapter id="adapter"
channel="channel"
object-name="example.domain:name=publisher"/>
提示

notification-listening-channel-adapter 在启动时会向一个 MBeanServer 注册,其默认的 bean 名称为 mbeanServer,这与使用 Spring 的 <context:mbean-server/> 元素时生成的 bean 名称恰好相同。如果你需要使用不同的名称,请务必包含 mbean-server 属性。

适配器还可以接受一个 NotificationFilter 引用和一个“回传”对象,用于提供随每个通知传递回的一些上下文信息。这两个属性都是可选的。扩展前面的示例以包含这些属性以及显式的 MBeanServer bean 名称,会生成以下示例:

<int-jmx:notification-listening-channel-adapter id="adapter"
channel="channel"
mbean-server="someServer"
object-name="example.domain:name=somePublisher"
notification-filter="notificationFilter"
handback="myHandback"/>

_Notification-listening 通道适配器是事件驱动的,并直接注册到 MBeanServer。它不需要任何轮询器配置。

备注

仅针对此组件,object-name 属性可以包含对象名称模式,例如 org.something:type=MyType,name=*。在这种情况下,适配器会接收来自所有匹配该模式的对象名称的 MBean 的通知。此外,object-name 属性可以包含对 <util:list> 对象名称模式的 SpEL 引用,如下例所示:

<jmx:notification-listening-channel-adapter id="manyNotificationsAdapter"
channel="manyNotificationsChannel"
object-name="#{patterns}"/>

<util:list id="patterns">
<value>org.foo:type=Foo,name=*</value>
<value>org.foo:type=Bar,name=*</value>
</util:list>

当启用 DEBUG 级别日志记录时,会记录已定位的 MBean 的名称。

通知发布通道适配器

通知发布通道适配器相对简单。其配置仅需一个 JMX 对象名称,如下例所示:

<context:mbean-export/>

<int-jmx:notification-publishing-channel-adapter id="adapter"
channel="channel"
object-name="example.domain:name=publisher"/>

同时,它要求上下文中必须存在一个 MBeanExporter。这就是为什么在前面的示例中也展示了 <context:mbean-export/> 元素。

当消息发送到此适配器的通道时,通知会从消息内容创建。如果负载是 String 类型,它将作为通知的 message 文本传递。任何其他负载类型则作为通知的 userData 传递。

JMX通知同样具有一个type属性,它应当是一个以点分隔的String字符串。提供type的方式有两种。系统始终优先采用与JmxHeaders.NOTIFICATION_TYPE键关联的消息头值。此外,您也可以在配置中提供备用的default-notification-type属性,如下例所示:

<context:mbean-export/>

<int-jmx:notification-publishing-channel-adapter id="adapter"
channel="channel"
object-name="example.domain:name=publisher"
default-notification-type="some.default.type"/>

属性轮询通道适配器

属性轮询通道适配器在需要定期检查通过 MBean 作为托管属性提供的某些值时非常有用。您可以像配置 Spring Integration 中的任何其他轮询适配器一样配置轮询器,也可以依赖默认轮询器。object-nameattribute-name 是必需的。MBeanServer 引用也是必需的。不过,默认情况下它会自动检查名为 mbeanServer 的 bean,与前面描述的通知监听通道适配器相同。以下示例展示了如何使用 XML 配置属性轮询通道适配器:

<int-jmx:attribute-polling-channel-adapter id="adapter"
channel="channel"
object-name="example.domain:name=someService"
attribute-name="InvocationCount">
<int:poller max-messages-per-poll="1" fixed-rate="5000"/>
</int-jmx:attribute-polling-channel-adapter>

树轮询通道适配器

树轮询通道适配器会查询 JMX MBean 树,并发送一条消息,其负载是与查询匹配的对象图。默认情况下,MBeans 会被映射为基本类型和简单对象,例如 MapList 和数组。这样做允许进行简单的转换,例如转换为 JSON。同时还需要一个 MBeanServer 引用。不过,默认情况下,它会自动检查名为 mbeanServer 的 bean,与前面描述的通知监听通道适配器相同。以下示例展示了如何使用 XML 配置树轮询通道适配器:

<int-jmx:tree-polling-channel-adapter id="adapter"
channel="channel"
query-name="example.domain:type=*">
<int:poller max-messages-per-poll="1" fixed-rate="5000"/>
</int-jmx:tree-polling-channel-adapter>

前面的示例包含了所选 MBean 的所有属性。您可以通过配置一个具有适当过滤器的 MBeanObjectConverter 来过滤属性。您可以使用 converter 属性将转换器作为对 bean 定义的引用提供,也可以使用内部的 <bean/> 定义。Spring Integration 提供了一个 DefaultMBeanObjectConverter,它可以在其构造函数参数中接收一个 MBeanAttributeFilter

Spring Integration 提供了两种标准过滤器。NamedFieldsMBeanAttributeFilter 允许您指定要包含的属性列表。NotNamedFieldsMBeanAttributeFilter 允许您指定要排除的属性列表。您也可以实现自己的过滤器。

操作调用通道适配器

操作调用通道适配器支持通过消息驱动方式调用MBean公开的任何托管操作。每次调用都需要指定待调用的操作名称和目标MBean的对象名称。这两项信息必须通过适配器配置显式提供,或分别通过JmxHeaders.OBJECT_NAMEJmxHeaders.OPERATION_NAME消息头传递:

<int-jmx:operation-invoking-channel-adapter id="adapter"
object-name="example.domain:name=TestBean"
operation-name="ping"/>

那么适配器只需要能够发现 mbeanServer bean。如果需要不同的 bean 名称,则通过 mbean-server 属性提供引用。

消息的有效载荷会被映射到操作的参数上(如果存在参数的话)。一个键为 String 类型的 Map 类型有效载荷会被视为名称/值对,而 List 或数组则作为简单的参数列表传递(没有显式的参数名称)。如果操作只需要单个参数值,有效载荷可以代表那个单一值。同样,如果操作不需要参数,有效载荷则会被忽略。

如果你希望为单一通用操作暴露一个通道,以便无需包含头部的消息能够调用它,那么最后一种方案效果很好。

操作调用出站网关

与操作调用通道适配器类似,Spring Integration 还提供了操作调用出站网关,当需要处理非空操作并获取返回值时,可以使用该组件。返回值将作为消息负载发送到网关指定的 reply-channel。以下示例展示了如何使用 XML 配置操作调用出站网关:

<int-jmx:operation-invoking-outbound-gateway request-channel="requestChannel"
reply-channel="replyChannel"
object-name="o.s.i.jmx.config:type=TestBean,name=testBeanGateway"
operation-name="testWithReturn"/>

如果您未提供 reply-channel 属性,回复消息将被发送到由 MessageHeaders.REPLY_CHANNEL 标头标识的通道。该标头通常由消息流的入口点(例如任何网关组件)自动创建。但是,如果消息流是通过手动创建 Spring Integration 消息并直接发送到通道而启动的,则必须显式指定消息标头或使用 reply-channel 属性。

MBean 导出器

当配置了 IntegrationMBeanExporter 时,Spring Integration 组件本身可以作为 MBean 暴露。要创建 IntegrationMBeanExporter 的实例,需要定义一个 bean 并提供对 MBeanServer 的引用以及域名(如果需要)。你可以省略域名,此时默认域为 org.springframework.integration。以下示例展示了如何声明 IntegrationMBeanExporter 实例及关联的 MBeanServer 实例:

<int-jmx:mbean-export id="integrationMBeanExporter"
default-domain="my.company.domain" server="mbeanServer"/>

<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true"/>
</bean>
important

MBean 导出器与 Spring 核心中提供的导出器是正交的。它注册消息通道和消息处理器,但不会注册自身。你可以通过使用标准的 <context:mbean-export/> 标签来暴露该导出器本身(以及 Spring Integration 中的某些其他组件)。该导出器附带了一些指标——例如,处理器数量和排队消息数量。

它还包含一个有用的操作,如有序关闭管理操作中所述。

Spring Integration 4.0 引入了 @EnableIntegrationMBeanExport 注解,以便在 @Configuration 类级别上方便地配置一个默认的 integrationMbeanExporter bean,其类型为 IntegrationMBeanExporter,并提供多个有用的选项。以下示例展示了如何配置此 bean:

@Configuration
@EnableIntegration
@EnableIntegrationMBeanExport(server = "mbeanServer", managedComponents = "input")
public class ContextConfiguration {

@Bean
public MBeanServerFactoryBean mbeanServer() {
return new MBeanServerFactoryBean();
}
}

如果你需要提供更多选项或拥有多个 IntegrationMBeanExporter bean(例如用于不同的 MBean 服务器,或为避免与标准 Spring MBeanExporter 冲突——例如通过 @EnableMBeanExport 引入的),你可以将 IntegrationMBeanExporter 配置为一个通用 bean。

MBean 对象名称

应用程序中的所有 MessageChannelMessageHandlerMessageSource 实例都由 MBean 导出器包装,以提供管理和监控功能。每种组件类型生成的 JMX 对象名称如下表所示:

表 1. MBean 对象名称

组件类型对象名称
MessageChannel`o.s.i:type=MessageChannel,name=<channelName>`
MessageSource`o.s.i:type=MessageSource,name=<channelName>,bean=<source>`
MessageHandler`o.s.i:type=MessageSource,name=<channelName>,bean=<source>`

sourceshandlers 对象名称中的 bean 属性可接受下表中的任一值:

表 2. bean ObjectName 部分

Bean 值描述
endpoint如果存在,则为封闭端点(例如 <service-activator>)的 bean 名称
anonymous表示封闭端点没有用户指定的 bean 名称,因此 JMX 名称为输入通道名称
internal用于 Spring Integration 默认的知名组件
handler/source以上均不适用。回退到被监控对象(处理器或源)的 toString() 方法

您可以通过在 object-name-static-properties 属性中提供对 Properties 对象的引用,来向对象名称追加自定义元素。

此外,自 Spring Integration 3.0 起,您可以通过设置 object-naming-strategy 属性来使用自定义的 ObjectNamingStrategy。这样做可以更好地控制 MBean 的命名,例如将所有集成 MBean 分组在 'Integration' 类型下。以下示例展示了一种可能的自定义命名策略实现:

public class Namer implements ObjectNamingStrategy {

private final ObjectNamingStrategy realNamer = new KeyNamingStrategy();
@Override
public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException {
String actualBeanKey = beanKey.replace("type=", "type=Integration,componentType=");
return realNamer.getObjectName(managedBean, actualBeanKey);
}

}

beanKey 参数是一个 String 类型,它包含标准的对象名称,以 default-domain 开头,并包含任何额外的静态属性。前面的示例将标准的 type 部分移动到了 componentType,并将 type 设置为 'Integration',从而可以在一个查询中选中所有 Integration MBean:my.domain:type=Integration,*。这样做还可以在诸如 VisualVM 这样的工具中,将这些 bean 分组到域下的一个树形条目中。

备注

默认的命名策略是 MetadataNamingStrategy。导出器会将 default-domain 传递给该对象,以便在解析 bean 键失败时生成一个回退对象名称。如果你的自定义命名策略是 MetadataNamingStrategy(或其子类),导出器则不会传递 default-domain。你必须在策略 bean 上自行配置它。

从版本5.1开始,如果bean名称(由对象名称中的name键表示)包含任何Java标识符(或句点.)中不允许的字符,则这些名称将被引号括起来。

JMX 改进

版本 4.2 引入了一些重要的改进,代表着对框架中 JMX 支持的一次相当重大的重构。这些改进显著提升了 JMX 统计信息收集的性能,并提供了更强的控制能力。然而,在一些特定(不常见)的情况下,这些变化可能会对用户代码产生影响。下面将详细说明这些变化,并在必要时给出注意事项。

@IntegrationManagedResource

@ManagedResource 注解类似,@IntegrationManagedResource 将类标记为有资格作为 MBean 导出。然而,仅当应用程序上下文包含 IntegrationMBeanExporter 时,它才会被导出。

某些 Spring Integration 类(位于 org.springframework.integration 包中)先前仅标注了 @ManagedResource 注解,现在则同时标注了 @ManagedResource@IntegrationManagedResource 注解。这是为了保持向后兼容性(参见下一项说明)。这类 MBean 可由任意上下文的 MBeanServerIntegrationMBeanExporter 导出(但不会同时被两者导出——如果两个导出器同时存在,当 bean 符合 managed-components 模式时,将由集成导出器负责导出该 bean)。

MBean Exporter Bean 名称模式

此前,managed-components 模式仅支持包含规则。如果 bean 名称匹配某个模式,则会被包含。现在,可以通过在模式前添加 ! 前缀来否定该模式。例如,!thing*, things 匹配所有不以 thing 开头但 things 除外(即包含 things)的 bean 名称。模式从左到右依次评估,第一个匹配的模式(无论是肯定还是否定)生效,后续模式不再应用。

注意

向模式中添加此语法会导致一个可能(尽管或许不太可能)的问题。如果你有一个名为 "!thing" 的 bean,并且在你的 MBean 导出器的 managed-components 模式中包含 !thing 模式,它将不再匹配;该模式现在会匹配所有不名为 thing 的 bean。在这种情况下,你可以在模式中使用 \ 来转义 !\!thing 模式会匹配名为 !thing 的 bean。

IntegrationMBeanExporter 变更

IntegrationMBeanExporter 不再实现 SmartLifecycle 接口。这意味着 start()stop() 操作不再可用于注册和注销 MBeans。现在,MBeans 在上下文初始化期间注册,并在上下文销毁时注销。

有序关闭托管操作

MBean 导出器允许通过 JMX 操作以有序方式关闭应用程序。该功能适用于停止 JVM 前的场景,其使用方法和操作说明详见有序关闭