JMX 支援

Spring Integration 提供了用於接收和釋出 JMX 通知 的通道介面卡。

您需要在專案中包含此依賴項

  • Maven

  • Gradle

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

入站通道介面卡允許輪詢 JMX MBean 屬性值,而出站通道介面卡允許呼叫 JMX MBean 操作。

通知監聽通道介面卡

通知監聽通道介面卡需要一個 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 屬性可以包含一個 SpEL 引用,指向一個 <util:list> 型別的物件名稱模式列表,示例如下:

<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 樹,併發送一個訊息,其負載是與查詢匹配的物件圖。預設情況下,MBean 被對映到基本型別和簡單物件,例如 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 屬性。

訊息的負載將被對映到操作的引數(如果存在)。一個鍵為 StringMap 型別負載被視為名稱/值對,而 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 屬性,回覆訊息將傳送到由 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 exporter 與 Spring core 中提供的 exporter 是正交的。它註冊訊息通道和訊息處理程式,但不註冊自身。您可以使用標準的 <context:mbean-export/> 標籤來暴露 exporter 本身(以及 Spring Integration 中的某些其他元件)。此 exporter 附帶了一些指標——例如,處理程式數量和佇列中訊息數量的計數。

它還有一個有用的操作,如有序關閉管理操作中所述。

Spring Integration 4.0 引入了 @EnableIntegrationMBeanExport 註解,以便在 @Configuration 類級別方便地配置一個預設的型別為 IntegrationMBeanExporterintegrationMbeanExporter 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 物件名稱

應用程式中的所有 MessageChannelMessageHandlerMessageSource 例項都由 MBean exporter 包裝,以提供管理和監控功能。下表列出了每種元件型別生成的 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>`

源和處理程式物件名稱中的 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',從而可以透過一個查詢選擇所有整合 MBean:my.domain:type=Integration,*。這樣做還可以將 bean 在 VisualVM 等工具的域下的一個樹狀條目下進行分組。

預設的命名策略是 MetadataNamingStrategy。如果解析 bean 鍵失敗,exporter 會將 default-domain 傳播到該物件,以便它生成一個備用的物件名稱。如果您的自定義命名策略是 MetadataNamingStrategy(或其子類),exporter 不會傳播 default-domain。您必須在您的策略 bean 上進行配置。

從版本 5.1 開始,任何 bean 名稱(由物件名稱中的 name 鍵表示)如果包含 Java 識別符號中不允許的任何字元(或句點 .),都將被引用(quoted)。

JMX 改進

版本 4.2 引入了一些重要的改進,代表了框架中 JMX 支援的相當大的改進。這些改進帶來了 JMX 統計資料收集的顯著效能提升,並提供了更多的控制。然而,在少數特定(不常見)情況下,它對使用者程式碼有一些影響。這些變更在下面進行了詳細說明,必要時會給出警告。

@IntegrationManagedResource

類似於 @ManagedResource 註解,@IntegrationManagedResource 標記一個類可以被匯出為 MBean。但是,只有當應用程式上下文中有 IntegrationMBeanExporter 時,它才會被匯出。

Spring Integration 中(在 org.springframework.integration 包中)的某些類以前使用 @ManagedResource 註解,現在同時使用 @ManagedResource@IntegrationManagedResource 註解。這是為了向後相容(參見下一項)。這些 MBean 可以由任何上下文的 MBeanServerIntegrationMBeanExporter 匯出(但不能同時由兩者匯出——如果兩者都存在,如果 bean 與 managed-components 模式匹配,則由整合 exporter 匯出)。

MBean Exporter Bean 名稱模式

以前,managed-components 模式僅是包含性的。如果 bean 名稱與其中一個模式匹配,它就會被包含。現在,模式可以透過在其前面加上 ! 進行否定。例如,!thing*, things 匹配所有不以 thing 開頭的 bean 名稱,除了 things。模式從左到右評估。第一個匹配(肯定或否定)獲勝,然後不再應用後續模式。

給模式新增此語法可能導致一個潛在(儘管可能不太可能)的問題。如果您有一個名為 "!thing" 的 bean,並且您在 MBean exporter 的 managed-components 模式中包含了 !thing 模式,它將不再匹配;該模式現在匹配所有名稱不是 thing 的 bean。在這種情況下,您可以在模式中用 \ 轉義 !\!thing 模式匹配名為 !thing 的 bean。
IntegrationMBeanExporter 變更

IntegrationMBeanExporter 不再實現 SmartLifecycle。這意味著 start()stop() 操作不再可用於註冊和登出 MBean。MBean 現在在上下文初始化期間註冊,並在上下文銷燬時登出。

有序關閉管理操作

MBean exporter 允許使用 JMX 操作以有序方式關閉應用程式。它旨在用於停止 JVM 之前。以下示例展示瞭如何使用它:

public void stopActiveComponents(long howLong)

其用法和操作在有序關閉中描述。