世界微資訊!Spring Integration 的 XMPP 通道適配器

2022-12-15 10:15:28 來源:51CTO博客

Spring Integration 為XMPP提供通道適配器。 XMPP 代表“可擴展消息傳遞和狀態協議”。

XMPP 描述了一種讓多個代理在分布式系統中相互通信的方法。 規范用例是發送和接收聊天消息,盡管 XMPP 可以(并且正在)用于其他類型的應用程序。 XMPP描述了一個參與者網絡。 在該網絡中,參與者可以直接相互稱呼并廣播狀態變化(例如“存在”)。


【資料圖】

XMPP提供了世界上一些最大的即時通訊網絡的基礎消息結構,包括Google Talk(GTalk,也可以在GMail內部使用)和Facebook Chat。 許多優秀的開源 XMPP 服務器都可用。 兩種流行的實現是Openfire和ejabberd。

Spring 集成通過提供 XMPP 適配器來提供對 XMPP 的支持,該適配器支持發送和接收 XMPP 聊天消息以及來自客戶名單中其他條目的狀態更改。

您需要將此依賴項包含在項目中:

    org.springframework.integration    spring-integration-xmpp    6.0.0

與其他適配器一樣,XMPP 適配器支持基于命名空間的便捷配置。 若要配置 XMPP 命名空間,請在 XML 配置文件的標頭中包含以下元素:

xmlns:int-xmpp="http://www.springframework.org/schema/integration/xmpp"xsi:schemaLocation="http://www.springframework.org/schema/integration/xmpp  https://www.springframework.org/schema/integration/xmpp/spring-integration-xmpp.xsd"

XMPP 連接

在使用入站或出站 XMPP 適配器加入 XMPP 網絡之前,參與者必須建立其 XMPP 連接。 連接到特定帳戶的所有 XMPP 適配器都可以共享此連接對象。 通常,這至少需要 、 和 。 若要創建基本 XMPP 連接,可以使用命名空間的便利性,如以下示例所示:??user????password????host??

為了更加方便,您可以依賴默認命名約定并省略該屬性。 缺省名稱 () 用于此連接 Bean。??id????xmppConnection??

如果 XMPP 連接過時,只要記錄(經過身份驗證)以前的連接狀態,就會嘗試使用自動登錄進行重新連接。 我們還注冊了一個 ,如果啟用了日志記錄級別,它將記錄連接事件。??ConnectionListener????DEBUG??

該屬性啟動名單偵聽器以處理來自其他用戶的傳入訂閱。 此功能并不總是可用于目標 XMPP 服務器。 例如,Google Cloud Messaging (GCM) 和 Firebase Cloud Messaging (FCM) 會完全禁用它。 若要關閉訂閱的名單偵聽器,可以在使用 XML 配置 () 或使用 Java 配置時為其配置空字符串。 這樣做也會在登錄階段禁用名單。 請參閱Roster.setRosterLoadedAtLogin(布爾值)了解更多信息。??subscription-mode????subscription-mode=""????XmppConnectionFactoryBean.setSubscriptionMode(null)??

XMPP 消息

Spring 集成提供了對發送和接收 XMPP 消息的支持。 為了接收它們,它提供了一個入站消息通道適配器。 為了發送它們,它提供了一個出站消息通道適配器。

入站消息通道適配器

Spring 集成適配器支持接收來自系統中其他用戶的聊天消息。 為此,入站消息通道適配器代表您以用戶身份“登錄”,并接收發送給該用戶的消息。 然后將這些消息轉發到您的 Spring 集成客戶端。 該元素為 XMPP 入站消息通道適配器提供配置支持。 以下示例演示如何配置它:??inbound-channel-adapter??

除了常規屬性(對于消息通道適配器)外,此適配器還需要引用 XMPP 連接。

XMPP 入站適配器是事件驅動的實現。 啟動時,它會注冊一個偵聽傳入的 XMPP 聊天消息。 它將收到的任何消息轉發到底層適配器,后者將它們轉換為 Spring 集成消息并將它們發送到指定的 . 停止后,它將取消注冊 .??Lifecycle????PacketListener????channel????PacketListener??

從 4.3 版開始,(及其 )支持注入要注冊的 ,以及內部實現。 有關更多信息,請參閱Javadoc?。??ChatMessageListeningEndpoint????????org.jivesoftware.smack.filter.StanzaFilter????XMPPConnection????StanzaListener??

版本 4.3 引入了 的屬性。 傳入表示評估上下文的根對象。 當您使用XMPP 擴展時,此選項很有用。 例如,對于 GCM 協議,我們可以使用以下表達式提取正文:??payload-expression????ChatMessageListeningEndpoint????org.jivesoftware.smack.packet.Message??

payload-expression="getExtension("google:mobile:data").json"

下面的示例提取 XHTML 協議的正文:

payload-expression="getExtension(T(org.jivesoftware.smackx.xhtmlim.packet.XHTMLExtension).NAMESPACE).bodies[0]"

為了簡化對 XMPP 消息中擴展的訪問,該變量已添加到 . 請注意,當消息中僅存在一個擴展名時,將添加它。 前面顯示操作的示例可以簡化為以下示例:??extension????EvaluationContext????namespace??

payload-expression="#extension.json"payload-expression="#extension.bodies[0]"

出站消息通道適配器

您還可以使用出站消息通道適配器向 XMPP 上的其他用戶發送聊天消息。 該元素為 XMPP 出站消息通道適配器提供配置支持。??outbound-channel-adapter??

適配器期望其輸入(至少)是類型的有效負載和標頭值,該值指定應將消息發送到哪個用戶。 要創建消息,可以使用類似于以下內容的 Java 代碼:??java.lang.String????XmppHeaders.CHAT_TO??

Message xmppOutboundMsg = MessageBuilder.withPayload("Hello, XMPP!" )            .setHeader(XmppHeaders.CHAT_TO, "userhandle")            .build();

還可以使用 XMPP 標頭擴充器支持來設置標頭,如以下示例所示:

  

從版本 4.3 開始,數據包擴展支持已添加到 (XML 配置中)。 除了常規和有效負載之外,現在您可以發送有效負載為 (填充到 ) 而不是 . 為方便起見,我們為 添加了一個選項。 它允許您注入 ,從而在運行時針對有效負載構建 。 對于這種情況,有效負載必須是 JSON 或 XML 格式的字符串,具體取決于 XEP 協議。??ChatMessageSendingMessageHandler????????String????org.jivesoftware.smack.packet.Message????org.jivesoftware.smack.packet.ExtensionElement????org.jivesoftware.smack.packet.Message.addExtension()????setBody()????extension-provider????ChatMessageSendingMessageHandler????org.jivesoftware.smack.provider.ExtensionElementProvider????ExtensionElement??

XMPP 存在

XMPP 還支持廣播狀態。 您可以使用此功能讓將你列入其名單的人員看到你的狀態更改。 這種情況一直發生在您的 IM 客戶端上。 您更改了離開狀態并設置了離開消息,每個將您列入其名單的人都會看到您的圖標或用戶名更改以反映此新狀態,并且可能會看到您的新“離開”消息。 如果您想接收通知或通知其他人狀態更改,您可以使用 Spring 集成的“狀態”適配器。

入站狀態消息通道適配器

Spring Integration provides an inbound presence message channel adapter, which supports receiving presence events from other users in the system who are on your roster. To do this, the adapter “logs in” as a user on your behalf, registers a, and forwards received presence update events as messages to the channel identified by theattribute. The payload of the message is aobject (seehttps://www.igniterealtime.org/builds/smack/docs/latest/javadoc/org/jivesoftware/smack/packet/Presence.html).??RosterListener????channel????org.jivesoftware.smack.packet.Presence??

Theelement provides configuration support for the XMPP inbound presence message channel adapter. The following example configures an inbound presence message channel adapter:??presence-inbound-channel-adapter??

除了通常的屬性外,此適配器還需要引用 XMPP 連接。 此適配器是事件驅動的,是一種實現。 它在啟動時注冊 ,在停止時注銷。??Lifecycle????RosterListener????RosterListener??

出站狀態消息通道適配器

Spring 集成還支持發送狀態事件,以便網絡中碰巧將您列入其名冊的其他用戶看到。 當您將消息發送到出站在線狀態消息通道適配器時,它會提取有效負載(應為 ) 并將其發送到 XMPP 連接,從而將您的狀態事件通告到網絡的其余部分。??org.jivesoftware.smack.packet.Presence??

該元素為 XMPP 出站狀態消息通道適配器提供配置支持。 以下示例演示如何配置出站狀態消息通道適配器:??presence-outbound-channel-adapter??

它也可以是輪詢使用者(如果它從可輪詢通道接收消息),在這種情況下,您需要注冊輪詢器。 以下示例演示如何執行此操作:

  

與其入站對應項一樣,它需要引用 XMPP 連接。

如果您依賴于 XMPP 連接 Bean 的缺省命名約定(如前所述?),并且您在應用程序上下文中只配置了一個 XMPP 連接 Bean,那么可以省略該屬性。 在這種情況下,將找到具有 name 的 Bean 并將其注入適配器。??xmpp-connection????xmppConnection??

高級配置

Spring Integration的XMPP支持基于Smack 4.0 API(https://www.igniterealtime.org/projects/smack/),它允許對XMPP Connection對象進行更復雜的配置。

如前所述,命名空間支持旨在簡化基本連接配置,并且僅支持幾個常見配置屬性。 但是,該對象定義了大約 20 個屬性,并且為所有屬性添加命名空間支持沒有實際價值。 因此,對于更復雜的連接配置,您可以將我們的實例配置為常規 bean,并將 a 作為構造函數參數注入該實例。 您可以直接在該實例上指定所需的每個屬性。 (帶有“p”命名空間的 bean 定義會很好用。 這樣,您可以直接設置 SSL(或任何其他屬性)。 以下示例演示如何執行此操作:??xmpp-connection????org.jivesoftware.smack.ConnectionConfiguration????XmppConnectionFactoryBean????org.jivesoftware.smack.ConnectionConfiguration????FactoryBean????ConnectionConfiguration??

                                                

Smack API 還提供了靜態初始值設定項,這可能會有所幫助。 對于更復雜的情況(例如注冊 SASL 機制),可能需要執行某些靜態初始值設定項。 其中一個靜態初始值設定項是 ,它允許您注冊支持的 SASL 機制。 對于這種復雜程度,我們建議使用 Spring Java 配置進行 XMPP 連接配置。 這樣,您可以通過 Java 代碼配置整個組件,并在適當的時間執行所有其他必要的 Java 代碼,包括靜態初始值設定項。 以下示例演示如何在 Java 中使用 SAL(簡單身份驗證和安全層)配置 XMPP 連接:??SASLAuthentication??

@Configurationpublic class CustomConnectionConfiguration {  @Bean  public XMPPConnection xmppConnection() {  SASLAuthentication.supportSASLMechanism("EXTERNAL", 0); // static initializer  ConnectionConfiguration config = new ConnectionConfiguration("localhost", 5223);  config.setKeystorePath("path_to_truststore.jks");  config.setSecurityEnabled(true);  config.setSocketFactory(SSLSocketFactory.getDefault());  return new XMPPConnection(config);  }}

有關使用 Java 進行應用程序上下文配置的更多信息,請參閱Spring 參考手冊中的以下部分。

XMPP 消息頭

彈簧集成 XMPP 適配器自動映射標準 XMPP 屬性。 默認情況下,這些屬性通過使用DefaultXmppHeaderMapper復制到 Spring Integration 和從 Spring Integration 復制。??MessageHeaders??

任何用戶定義的標頭都不會復制到 XMPP 消息或從 XMPP 消息復制,除非由 的 或 屬性顯式指定。??requestHeaderNames????replyHeaderNames????DefaultXmppHeaderMapper??

映射用戶定義的標頭時,這些值還可以包含簡單的通配符模式(例如“thing*”或“*thing”)。

從版本 4.1 開始,(的超類 )允許您配置屬性的令牌(除了 之外),以映射所有用戶定義的標頭。??AbstractHeaderMapper????DefaultXmppHeaderMapper????NON_STANDARD_HEADERS????requestHeaderNames????STANDARD_REQUEST_HEADERS??

該類標識要由 :??org.springframework.xmpp.XmppHeaders????DefaultXmppHeaderMapper??

??xmpp_from????xmpp_subject????xmpp_thread????xmpp_to????xmpp_type??

從版本 4.3 開始,您可以通過在標頭映射前面加上 來否定標頭映射中的模式。 否定模式獲得優先級,因此諸如不映射、或 的列表。 該列表確實映射了標準標頭加上 和 。??!????STANDARD_REQUEST_HEADERS,thing1,thing*,!thing2,!thing3,qux,!thing1????thing1????thing2????thing3????thing4????qux??

如果你有一個用戶定義的標頭,該標頭以您希望映射的標頭開頭,則可以使用以下方法對其進行轉義: . 在該示例中,將映射標準請求標頭和。??!????\????STANDARD_REQUEST_HEADERS,\!myBangHeader????!myBangHeader??

XMPP 擴展

擴展將“可擴展”放在“可擴展消息傳遞和狀態協議”中。

XMPP 基于 XML,XML是一種支持稱為命名空間的概念的數據格式。 通過命名空間,您可以向 XMPP 添加原始規范中未定義的位。 XMPP 規范特意只描述了一組核心功能:

客戶端如何連接到服務器加密 (SSL/TLS)認證服務器如何相互通信以中繼消息其他一些基本構建塊

實現這一點后,您就擁有一個 XMPP 客戶端,可以發送您喜歡的任何類型的數據。 但是,您可能需要做的不僅僅是基礎知識。 例如,您可能需要在郵件中包含格式(粗體、斜體等),這在核心 XMPP 規范中未定義。 好吧,你可以想出一種方法來做到這一點,但是,除非其他人都像你一樣做,否則沒有其他軟件可以解釋它(他們忽略他們無法理解的命名空間)。

為了解決這個問題,XMPP標準基金會(XSF)發布了一系列額外的文檔,稱為XMPP擴展協議(XEP)。 通常,每個 XEP 都描述一個特定的活動(從消息格式到文件傳輸、多用戶聊天等等)。 它們還為每個人提供了用于該活動的標準格式。

Smack API 提供了許多 XEP 實現及其項目。 從 Spring Integration 4.3 版開始,您可以將任何 XEP 與現有的 XMPP 通道適配器一起使用。??extensions????experimental??

為了能夠處理 XEP 或任何其他自定義 XMPP 擴展,您必須提供 Smack 的預配置。 您可以使用 Java 代碼執行此操作,如以下示例所示:??ProviderManager????static??

ProviderManager.addIQProvider("element", "namespace", new MyIQProvider());ProviderManager.addExtensionProvider("element", "namespace", new MyExtProvider());

您還可以在特定實例中使用配置文件,并使用 JVM 參數訪問它,如以下示例所示:??.providers??

-Dsmack.provider.file=file:///c:/my/provider/mycustom.providers

該文件可能如下所示:??mycustom.providers??

    query    jabber:iq:time    org.jivesoftware.smack.packet.Time    query    https://jabber.org/protocol/disco#items    org.jivesoftware.smackx.provider.DiscoverItemsProvider    subscription    https://jabber.org/protocol/pubsub    org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider

例如,最流行的XMPP消息傳遞擴展是Google Cloud Messaging(GCM)。 Smack 庫提供了用于此目的。 默認情況下,它使用資源向類路徑中的 jar 注冊該類,如以下 Maven 示例所示:??org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider????smack-experimental????experimental.providers??

    gcm    google:mobile:data    org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider

此外,允許目標消息傳遞協議解析傳入數據包并構建傳出數據包,如以下示例所示:??GcmPacketExtension??

GcmPacketExtension gcmExtension = (GcmPacketExtension) xmppMessage.getExtension(GcmPacketExtension.NAMESPACE);String message = gcmExtension.getJson());
GcmPacketExtension packetExtension = new GcmPacketExtension(gcmJson);Message smackMessage = new Message();smackMessage.addExtension(packetExtension);

有關詳細信息,請參閱本章前面的入站消息通道適配器和出站消息通道適配器。

標簽: 通道適配器 命名空間 有效負載

上一篇:天天資訊:Linux安裝docker、docker-compose
下一篇:期末復習二