JMX Support

Spring Integration 为接收和发布 JMX 通知提供了通道适配器。 你需要将此依赖项包含在你的项目中:

  • Maven

  • Gradle

<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-jmx</artifactId>
    <version>{project-version}</version>
</dependency>
compile "org.springframework.integration:spring-integration-jmx:{project-version}"

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

Notification-listening Channel Adapter

针对通知进行侦听的通道适配器需要一个 JMX ObjectName,用于发布将该侦听器注册到的通知的 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 和“handback”对象的引用,以提供随每个通知回传的某些上下文。这两个属性都是可选的。将前面的示例扩展为包括那些属性以及一个显式的 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"/>

针对_通知进行侦听的通道适配器是事件驱动的,并直接使用 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 的名称。

Notification-publishing Channel Adapter

通知发布通道适配器相对简单。它只需要在配置中提供一个 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"/>

Attribute-polling Channel Adapter

当您需要定期检查通过 MBean 按受管理属性提供的一些值时,属性轮询通道适配器很有用。您可通过与 Spring Integration 中的任何其他轮询适配器相同的方式配置轮询器(或您可以依赖默认轮询器)。需要 object-nameattribute-name。还需要 MBeanServer 引用。但是,默认情况下,它会自动检查一个名为 mbeanServer 的 Bean,与通知侦听通道适配器 described earlier 相同。以下示例展示了如何使用 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>

Tree-polling Channel Adapter

树形轮询通道适配器查询 JMX MBean 树,并发送消息,其有效负载为与查询相匹配的对象图表。默认情况下,MBean 映射至基本类型和简单对象,如 MapList 和数组。这样做允许实现简单转换,例如 JSON。还需要 MBeanServer 引用。但是,默认情况下,它会自动检查一个名为 mbeanServer 的 Bean,与通知侦听通道适配器 described earlier 相同。以下示例展示了如何使用 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 让你可以指定要排除的属性列表。你还可以实现自己的滤镜。

Operation-invoking Channel Adapter

调用操作通道适配器能够对 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 属性。

如果存在的话,消息的负载会映射到操作的参数。键为 StringMap 类型负载会被视为名称/值对,而 List 或数组会作为简单的参数列表传递(没有显式的参数名称)。如果操作需要一个参数值,则负载可以表示那个单独的值。此外,如果操作不需要参数,则会忽略负载。

如果你希望为单个常见操作公开一个通道,由不需要包含头的消息调用,那么最后一个选项很好用。

Operation-invoking Outbound Gateway

与调用操作通道适配器类似,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 属性,则答复消息会发送到由 IntegrationMessageHeaderAccessor.REPLY_CHANNEL 头标识的通道。通常由进入消息流的入口点自动创建该头,例如任何网关组件。但是,如果通过手动创建一个 Spring Integration 消息并将其直接发送到一个通道来启动该消息流,那么你必须显式指定消息头或使用 reply-channel 属性。

MBean Exporter

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>

这个 MBean 导出器与 Spring 核心提供的导出器是正交的。它注册消息通道和消息处理程序,但不会注册自身。你可以使用标准的 <context:mbean-export/> 标记公开导出器本身(和 Spring Integration 中的某些其他组件)。导出器有一些度量标准附加到它上,例如,处理程序的数量和排队消息的数量。 它还具有一些有用的操作,如 Orderly Shutdown Managed Operation 中所述。

Spring Integration 4.0 引入了 @EnableIntegrationMBeanExport 注解,以便在 @Configuration 类级别方便地配置一个带有几个有用的选项的默认 integrationMBeanExporter 类型为 IntegrationMBeanExporter 的 bean。以下示例展示了如何配置此 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 Object Names

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

Table 1. MBean Object Names
Component Type Object Name

MessageChannel

  `o.s.i:type=MessageChannel,name=&lt;channelName&gt;`

MessageSource

  `o.s.i:type=MessageSource,name=&lt;channelName&gt;,bean=&lt;source&gt;`

MessageHandler

  `o.s.i:type=MessageSource,name=&lt;channelName&gt;,bean=&lt;source&gt;`

资源和处理程序的对象名称中的 bean 属性采用以下表格中的某个值:

Table 2. bean ObjectName Part
Bean Value Description

endpoint

如果存在包围端点的 bean 名称(例如 &lt;service-activator&gt;)。

anonymous

包围端点没有用户指定的 bean 名称的指示,所以 JMX 名称是输入通道名称。

internal

对于众所周知的 Spring Integration 默认组件。

handler/source

以上均不符合。回退到所监控对象(处理程序或来源)的 toString() 方法。

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

此外,自 Spring Integration 3.0 起,您可以通过设置`object-naming-strategy`属性来使用自定义 link:https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jmx/export/naming/ObjectNamingStrategy.html[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 设置为“集成”,从而允许在一次查询中选择所有集成 MBean:my.domain:type=Integration,*。这样做还会在可视化 VM 等工具的域下将 Bean 分组到一个树条目下。

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

从版本 5.1 开始,如果任何 Bean 名称(由对象名称中的 name 键表示)包含 Java 标识符(或句点 “.”) 中不允许的任何字符,则该名称将被引用。

JMX Improvements

版本 4.2 引入了一些重要改进,表示框架中的 JMX 支持进行了一次相当大的检修。这导致 JMX 统计信息收集的性能有了显着的提升,并且对其控制功能更强。但是,在一些特定的(不常见)情况下,它对于用户代码具有一定的影响。下面将详细介绍这些更改,在必要时还会予以提醒。

@IntegrationManagedResource

Similar to the @ManagedResource annotation, the @IntegrationManagedResource marks a class as being eligible to be exported as an MBean. However, it is exported only if the application context has an IntegrationMBeanExporter.

某些 Spring Integration 类(在 org.springframework.integration 包中)以前标注有 @ManagedResource,现在还同时标注了 @ManagedResource@IntegrationManagedResource。这是出于向后兼容性的考虑(请参阅下一条)。此类 MBean 由任何上下文 MBeanServerIntegrationMBeanExporter(但不是两者,如果同时出现这两个导出器,如果该 Bean 匹配 managed-components 模式,该 Bean 将由集成导出器导出)导出。

MBean Exporter Bean Name Patterns

Previously, the managed-components patterns were inclusive only. If a bean name matched one of the patterns, it would be included. Now, the pattern can be negated by prefixing it with !. For example, !thing*, things matches all bean names that do not start with thing except things. Patterns are evaluated left to right. The first match (positive or negative) wins, and then no further patterns are applied.

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

IntegrationMBeanExporter changes

The IntegrationMBeanExporter no longer implements SmartLifecycle. This means that start() and stop() operations are no longer available to register and unregister MBeans. The MBeans are now registered during context initialization and unregistered when the context is destroyed.

Orderly Shutdown Managed Operation

MBean 导出器允许 JMX 操作以一种协调的方式关闭应用程序。它的目的是在停止 JVM 之前使用。以下示例展示了如何使用它:

public void stopActiveComponents(long howLong)

其使用和操作在 Orderly Shutdown中进行了描述。