XMPP Support

Spring Integration 为 XMPP 提供通道适配器。XMPP 代表 “Extensible Messaging and Presence Protocol”。

Spring Integration provides channel adapters for XMPP. XMPP stands for “Extensible Messaging and Presence Protocol”.

XMPP 描述了一种在分布式系统中多个代理互相通信的方式。规范的用例是发送和接收聊天消息,尽管 XMPP 可以(并且已)用于其他类型的应用程序。XMPP 描述了一个演员网络。在该网络中,演员可以直接互相联系并广播状态更改(例如,“状态”)。

XMPP describes a way for multiple agents to communicate with each other in a distributed system. The canonical use case is to send and receive chat messages, though XMPP can be (and is) used for other kinds of applications. XMPP describes a network of actors. Within that network, actors may address each other directly and broadcast status changes (such as “presence”).

XMPP 提供消息传递结构,它是世界上一些最大的即时消息网络的基础,包括 Google Talk(GTalk,也可以从 GMail 中使用)和 Facebook 聊天。有许多优秀的开源 XMPP 服务器可用。两个流行的实现是 Openfireejabberd

XMPP provides the messaging fabric that underlies some of the biggest instant messaging networks in the world, including Google Talk (GTalk, which is also available from within GMail) and Facebook Chat. Many good open-source XMPP servers are available. Two popular implementations are Openfire and ejabberd.

Spring Integration 通过提供 XMPP 适配器来为 XMPP 提供支持,这些适配器既支持发送 XMPP 聊天消息,也支持接收来自客户端名单中其他条目 XMPP 聊天消息和状态更改。

Spring integration provides support for XMPP by providing XMPP adapters, which support sending and receiving both XMPP chat messages and presence changes from other entries in a client’s roster.

你需要将此依赖项包含在你的项目中:

You need to include this dependency into your project:

  • Maven

  • Gradle

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

与其他适配器一样,XMPP 适配器附带了对基于命名空间的便捷配置的支持。要配置 XMPP 命名空间,请在 XML 配置文件的头中包含以下元素:

As with other adapters, the XMPP adapters come with support for a convenient namespace-based configuration. To configure the XMPP namespace, include the following elements in the headers of your XML configuration file:

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 Connection

在使用入站或出站 XMPP 适配器参与 XMPP 网络之前,一个演员必须建立其 XMPP 连接。连接到特定帐户的所有 XMPP 适配器都可以共享此连接对象。通常,这至少需要“用户”、“密码”和“主机”。要创建基本的 XMPP 连接,您可以使用命名空间的便捷方式,如下例所示:

Before using inbound or outbound XMPP adapters to participate in the XMPP network, an actor must establish its XMPP connection. All XMPP adapters connected to a particular account can share this connection object. Typically, this requires (at a minimum) user, password, and host. To create a basic XMPP connection, you can use the convenience of the namespace, as the following example shows:

<int-xmpp:xmpp-connection
    id="myConnection"
    user="user"
    password="password"
    host="host"
    port="port"
    resource="theNameOfTheResource"
    subscription-mode="accept_all"/>

为了更方便,您可以依赖默认命名约定并省略 id 属性。此连接 Bean 将使用默认名称(xmppConnection)。

For added convenience, you can rely on the default naming convention and omit the id attribute. The default name (xmppConnection) is used for this connection bean.

如果 XMPP 连接出现中断,只要之前的连接状态已被记录(经过身份验证),就会进行重新连接尝试,同时自动登录。我们还会注册一个 ConnectionListener,如果启用了 “DEBUG” 级别的日志记录,它将记录连接事件。

If the XMPP connection goes stale, reconnection attempts are made with an automatic login as long as the previous connection state was logged (authenticated). We also register a ConnectionListener, which logs connection events if the DEBUG logging level is enabled.

subscription-mode 属性初始化目录监听器以处理其他用户的来信订阅。此功能并不总是可用于目标 XMPP 服务器。例如,Google Cloud Messaging (GCM) 和 Firebase Cloud Messaging (FCM) 完全禁用了该功能。要关闭订阅的目录监听器,可以在使用 XML 配置时将其配置为空字符串(subscription-mode=""),或者在使用 Java 配置时将其配置为 XmppConnectionFactoryBean.setSubscriptionMode(null)。这样做也会在登录阶段禁用目录。请参阅 Roster.setRosterLoadedAtLogin(boolean) 了解更多信息。

The subscription-mode attribute initiates the roster listener to deal with incoming subscriptions from other users. This functionality is not always available for the target XMPP servers. For example, Google Cloud Messaging (GCM) and Firebase Cloud Messaging (FCM) fully disable it. To switch off the roster listener for subscriptions, you can configure it with an empty string when using XML configuration (subscription-mode="") or with XmppConnectionFactoryBean.setSubscriptionMode(null) when using Java Configuration. Doing so disables the roster at the login phase as well. See Roster.setRosterLoadedAtLogin(boolean) for more information.

XMPP Messages

Spring Integration 为发送和接收 XMPP 消息提供支持。为接收它们,它提供了一个入站消息通道适配器。为发送它们,它提供了一个出站消息通道适配器。

Spring Integration provides support for sending and receiving XMPP messages. For receiving them, it offers an inbound message channel adapter. For sending them, it offers an outbound message channel adapter.

Inbound Message Channel Adapter

Spring Integration 适配器支持接收系统中其他用户的聊天消息。为此,入站消息通道适配器会代表您以一个用户的身份“登录”,并接收发送给该用户的消息。这些消息然后被转发到您的 Spring Integration 客户端。inbound-channel-adapter (入站通道适配器) 元素为 XMPP 入站消息通道适配器提供配置支持。以下示例演示如何配置此适配器:

The Spring Integration adapters support receiving chat messages from other users in the system. To do so, the inbound message channel adapter “logs in” as a user on your behalf and receives the messages sent to that user. Those messages are then forwarded to your Spring Integration client. The inbound-channel-adapter element provides Configuration support for the XMPP inbound message channel adapter. The following example shows how to configure it:

<int-xmpp:inbound-channel-adapter id="xmppInboundAdapter"
	channel="xmppInbound"
	xmpp-connection="testConnection"
	payload-expression="getExtension('google:mobile:data').json"
	stanza-filter="stanzaFilter"
	auto-startup="true"/>

除了通常的属性(对于消息通道适配器)之外,此适配器还需要引用一个 XMPP 连接。

Along with the usual attributes (for a message channel adapter), this adapter also requires a reference to an XMPP Connection.

XMPP 入站适配器是事件驱动的和 Lifecycle 实现。启动时,它会注册一个 PacketListener,监听传入的 XMPP 聊天消息。它会将任何接收到的消息转发到底层适配器,后者会将它们转换为 Spring Integration 消息并将它们发送到指定的 channel (通道)。停止时,它会取消注册 PacketListener

The XMPP inbound adapter is event-driven and a Lifecycle implementation. When started, it registers a PacketListener that listens for incoming XMPP chat messages. It forwards any received messages to the underlying adapter, which converts them to Spring Integration messages and sends them to the specified channel. When stopped, it unregisters the PacketListener.

从版本 4.3 开始,ChatMessageListeningEndpoint(及其 <int-xmpp:inbound-channel-adapter>)支持注入 org.jivesoftware.smack.filter.StanzaFilter,以便在提供的 XMPPConnection,与内部 StanzaListener 实现一起注册。请参阅 Javadoc 了解更多信息。

Starting with version 4.3, the ChatMessageListeningEndpoint (and its <int-xmpp:inbound-channel-adapter>) supports the injection of a org.jivesoftware.smack.filter.StanzaFilter to be registered on the provided XMPPConnection, together with an internal StanzaListener implementation. See the Javadoc for more information.

版本 4.3 为 ChatMessageListeningEndpoint 引入了 payload-expression 属性。传入 org.jivesoftware.smack.packet.Message 表示评估上下文的根对象。使用 XMPP extensions 时,此选项很有用。例如,对于 GCM 协议,我们可以使用以下表达式提取正文:

Version 4.3 introduced the payload-expression attribute for the ChatMessageListeningEndpoint. The incoming org.jivesoftware.smack.packet.Message represents a root object for the evaluation context. This option is useful when you use XMPP extensions. For example, for the GCM protocol we can extract the body by using the following expression:

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

以下示例提取 XHTML 协议的正文:

The following example extracts the body for the XHTML protocol:

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

为了简化访问 XMPP 消息中的扩展,将 extension 变量添加到 EvaluationContext 中。请注意,当消息中仅存在一个扩展时,它会被添加进去。前面显示 namespace 操作的示例可以简化为以下示例:

To simplify access to the extension in the XMPP Message, the extension variable is added into the EvaluationContext. Note that it is added when only one extension is present in the message. The preceding examples that show the namespace manipulations can be simplified to the following example:

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

Outbound Message Channel Adapter

您还可以使用出站消息通道适配器向 XMPP 上的其他用户发送聊天消息。 outbound-channel-adapter 元素为 XMPP 出站消息通道适配器提供配置支持。

You can also send chat messages to other users on XMPP by using the outbound message channel adapter. The outbound-channel-adapter element provides configuration support for the XMPP outbound message channel adapter.

<int-xmpp:outbound-channel-adapter id="outboundEventAdapter"
						channel="outboundEventChannel"
						xmpp-connection="testConnection"/>

该适配器希望其输入至少包含类型为 java.lang.String 的有效负载和 XmppHeaders.CHAT_TO 的标头值,其中指定消息应发送给哪个用户。要创建消息,您可以使用类似于以下内容的 Java 代码:

The adapter expects its input to be (at a minimum) a payload of type java.lang.String and a header value for XmppHeaders.CHAT_TO that specifies to which user the message should be sent. To create a message, you can use Java code similar to the following:

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

您还可以使用 XMPP 标头强化程序支持设置标头,如下例所示:

You can also set the header by using the XMPP header-enricher support, as the following example shows:

<int-xmpp:header-enricher input-channel="input" output-channel="output">
	<int-xmpp:chat-to value="test1@example.org"/>
</int-xmpp:header-enricher>

从 4.3 版开始,已将数据包扩展支持添加到 ChatMessageSendingMessageHandler (XML 配置中的 <int-xmpp:outbound-channel-adapter>)。除了常规的 Stringorg.jivesoftware.smack.packet.Message 有效负载之外,您现在可以使用 org.jivesoftware.smack.packet.XmlElement(填充到 org.jivesoftware.smack.packet.Message.addExtension()) 而不是 setBody() 的有效负载来发送消息。为了方便起见,我们为 ChatMessageSendingMessageHandler 添加了 extension-provider 选项。它允许您注入 org.jivesoftware.smack.provider.ExtensionElementProvider,它在运行时根据有效负载构建 XmlElement。对于这种情况,有效负载必须是 JSON 或 XML 格式的字符串,具体取决于 XEP 协议。

Starting with version 4.3, the packet extension support has been added to the ChatMessageSendingMessageHandler (the <int-xmpp:outbound-channel-adapter> in XML configuration). Along with the regular String and org.jivesoftware.smack.packet.Message payload, now you can send a message with a payload of org.jivesoftware.smack.packet.XmlElement (which is populated to the org.jivesoftware.smack.packet.Message.addExtension()) instead of setBody(). For convenience, we added an extension-provider option for the ChatMessageSendingMessageHandler. It lets you inject org.jivesoftware.smack.provider.ExtensionElementProvider, which builds an XmlElement against the payload at runtime. For this case, the payload must be a string in JSON or XML format, depending on the XEP protocol.

XMPP Presence

XMPP 还支持广播状态。您可以使用此功能让您通讯录中的人查看您的状态更改。这始终发生在您的 IM 客户端中。您更改为离开状态并设置离开消息,通讯录中拥有您的人会看到您的图标或用户名发生更改以反映此新状态,并且可能会看到您的新“离开”消息。如果您想接收通知或通知其他人状态已更改,可以使用 Spring Integration 的“presence”适配器。

XMPP also supports broadcasting state. You can use this ability to let people who have you on their roster see your state changes. This happens all the time with your IM clients. You change your away status and set an away message, and everybody who has you on their roster sees your icon or username change to reflect this new state and might see your new “away” message. If you would like to receive notifications or notify others of state changes, you can use Spring Integration’s “presence” adapters.

Inbound Presence Message Channel Adapter

Spring Integration 提供了一个入站出席消息通道适配器,它支持从您花名册中的系统中其他人那里接收出席事件。为此,适配器 “logs in” 代表您作为用户注册 RosterListener,并将接收到的出席更新事件转发为消息,发送到由 channel 属性标识的通道。消息的有效负载为 org.jivesoftware.smack.packet.Presence 对象(请参阅 [role="bare"][role="bare"]https://www.igniterealtime.org/builds/smack/docs/latest/javadoc/org/jivesoftware/smack/packet/Presence.html)。

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 RosterListener, and forwards received presence update events as messages to the channel identified by the channel attribute. The payload of the message is a org.jivesoftware.smack.packet.Presence object (see [role="bare"]https://www.igniterealtime.org/builds/smack/docs/latest/javadoc/org/jivesoftware/smack/packet/Presence.html).

presence-inbound-channel-adapter 元素为 XMPP 入站显示消息通道适配器提供配置支持。以下示例配置入站显示消息通道适配器:

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

<int-xmpp:presence-inbound-channel-adapter channel="outChannel"
		xmpp-connection="testConnection" auto-startup="false"/>

除了通常的属性之外,此适配器还需要引用 XMPP 连接。此适配器是事件驱动的和 Lifecycle 实现。启动时注册 RosterListener,停止时取消注册该 RosterListener

Along with the usual attributes, this adapter requires a reference to an XMPP Connection. This adapter is event-driven and a Lifecycle implementation. It registers a RosterListener when started and unregisters that RosterListener when stopped.

Outbound Presence Message Channel Adapter

Spring Integration 还支持发送显示事件,供您通讯录中碰巧拥有您的网络中的其他用户查看。当您向出站显示消息通道适配器发送消息时,它会提取有效负载(预计为 org.jivesoftware.smack.packet.Presence 类型)并将其发送到 XMPP 连接,从而向网络中的其他人广播您的显示事件。

Spring Integration also supports sending presence events to be seen by other users in the network who happen to have you on their roster. When you send a message to the outbound presence message channel adapter, it extracts the payload (which is expected to be of type org.jivesoftware.smack.packet.Presence) and sends it to the XMPP Connection, thus advertising your presence events to the rest of the network.

presence-outbound-channel-adapter 元素为 XMPP 出站显示消息通道适配器提供配置支持。以下示例显示如何配置出站显示消息通道适配器:

The presence-outbound-channel-adapter element provides configuration support for the XMPP outbound presence message channel adapter. The following example shows how to configure an outbound presence message channel adapter:

<int-xmpp:presence-outbound-channel-adapter id="eventOutboundPresenceChannel"
	xmpp-connection="testConnection"/>

如果它从可轮询通道接收消息,它也可以是轮询消费者,在这种情况下,您需要注册一个轮询器。以下示例演示如何执行此操作:

It can also be a polling consumer (if it receives messages from a pollable channel) in which case you would need to register a poller. The following example shows how to do so:

<int-xmpp:presence-outbound-channel-adapter id="pollingOutboundPresenceAdapter"
		xmpp-connection="testConnection"
		channel="pollingChannel">
	<int:poller fixed-rate="1000" max-messages-per-poll="1"/>
</int-xmpp:presence-outbound-channel-adapter>

与入站对应项一样,它需要引用 XMPP 连接。

Like its inbound counterpart, it requires a reference to an XMPP Connection.

如果您依赖于 XMPP 连接 bean(described earlier)的默认命名约定,并且仅在应用程序上下文中配置了一个 XMPP 连接 bean,那么您可以省略 xmpp-connection 属性。在这种情况下,将会找到并注入名为 xmppConnection 的 bean 到此适配器中。

If you rely on the default naming convention for an XMPP Connection bean (described earlier) and you have only one XMPP Connection bean configured in your application context, you can omit the xmpp-connection attribute. In that case, the bean with named xmppConnection is located and injected into the adapter.

Advanced Configuration

Spring Integration 的 XMPP 支持基于 Smack 4.0 API ([role="bare"][role="bare"]https://www.igniterealtime.org/projects/smack/),该 API 允许对 XMPP 连接对象进行更为复杂的配置。

Spring Integration’s XMPP support is based on the Smack 4.0 API ([role="bare"]https://www.igniterealtime.org/projects/smack/), which allows more complex configuration of the XMPP Connection object.

作为 stated earlierxmpp-connection 名称空间的支持旨在简化基本连接配置,仅支持一些常见的配置属性。然而,org.jivesoftware.smack.ConnectionConfiguration 对象定义了大约 20 个属性,为所有这些属性添加名称空间支持没有任何实际价值。所以,对于更复杂的连接配置,你可以将 XmppConnectionFactoryBean 的实例配置为常规 bean,并将 org.jivesoftware.smack.ConnectionConfiguration 注入到该 FactoryBean 的构造函数参数。你可以在该 ConnectionConfiguration 实例直接指定每个所需的属性。(带有“p”名称空间的 bean 定义将工作得很好。)通过这种方式,你可以直接设置 SSL(或任何其他属性)。下面的示例演示了如何执行此操作:

As stated earlier, the xmpp-connection namespace support is designed to simplify basic connection configuration and supports only a few common configuration attributes. However, the org.jivesoftware.smack.ConnectionConfiguration object defines about 20 attributes, and adding namespace support for all of them offers no real value. So, for more complex connection configurations, you can configure an instance of our XmppConnectionFactoryBean as a regular bean and inject a org.jivesoftware.smack.ConnectionConfiguration as a constructor argument to that FactoryBean. You can specify every property you need directly on that ConnectionConfiguration instance. (A bean definition with the 'p' namespace would work well.) This way, you can directly set SSL (or any other attributes). The following example shows how to do so:

<bean id="xmppConnection" class="o.s.i.xmpp.XmppConnectionFactoryBean">
    <constructor-arg>
        <bean class="org.jivesoftware.smack.ConnectionConfiguration">
            <constructor-arg value="myServiceName"/>
            <property name="socketFactory" ref="..."/>
        </bean>
    </constructor-arg>
</bean>

<int:channel id="outboundEventChannel"/>

<int-xmpp:outbound-channel-adapter id="outboundEventAdapter"
    channel="outboundEventChannel"
    xmpp-connection="xmppConnection"/>

Smack API 还提供静态初始化程序,这可能会很有用。对于更复杂的情况(例如注册 SASL 机制),您可能需要执行某些静态初始化程序。其中一个静态初始化程序是 SASLAuthentication,它允许您注册受支持的 SASL 机制。对于这种复杂级别,我们建议将 Spring Java 配置用于 XMPP 连接配置。这样,您可以通过 Java 代码配置整个组件,并在适当的时候执行包括静态初始化程序在内的所有其他必要的 Java 代码。以下示例显示如何使用 Java 中的 SASL(简单认证和安全层)配置 XMPP 连接:

The Smack API also offers static initializers, which can be helpful. For more complex cases (such as registering a SASL mechanism), you may need to execute certain static initializers. One of those static initializers is SASLAuthentication, which lets you register supported SASL mechanisms. For that level of complexity, we recommend using Spring Java configuration for the XMPP connection configuration. That way, you can configure the entire component through Java code and execute all other necessary Java code, including static initializers, at the appropriate time. The following example shows how to configure an XMPP connection with an SASL (Simple Authentication and Security Layer) in Java:

@Configuration
public 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 Reference Manual 中的以下部分。

For more information on using Java for application context configuration, see the following section in the Spring Reference Manual.

XMPP Message Headers

Spring Integration XMPP Adapter 会自动映射标准 XMPP 属性。默认情况下,这些属性使用 DefaultXmppHeaderMapper 技术从 Spring Integration MessageHeaders 复制到其中。

The Spring Integration XMPP Adapters automatically map standard XMPP properties. By default, these properties are copied to and from Spring Integration MessageHeaders by using DefaultXmppHeaderMapper.

除非明确由 DefaultXmppHeaderMapperrequestHeaderNamesreplyHeaderNames 属性指定,否则任何用户定义头都不被复制到 XMPP 消息中或从中复制。

Any user-defined headers are not copied to or from an XMPP Message, unless explicitly specified by the requestHeaderNames or replyHeaderNames properties of the DefaultXmppHeaderMapper.

映射用户定义的标头时,这些值还可以包含简单的通配符模式(例如“things*”或“*things”)。

When mapping user-defined headers, the values can also contain simple wildcard patterns (such "thing*" or "*thing").

从 4.1 版开始,AbstractHeaderMapperDefaultXmppHeaderMapper 的超类)允许您将 NON_STANDARD_HEADERS 令牌配置为 requestHeaderNames 属性(除了 STANDARD_REQUEST_HEADERS),以映射所有用户定义头。

Starting with version 4.1, AbstractHeaderMapper (a superclass of DefaultXmppHeaderMapper) lets you configure the NON_STANDARD_HEADERS token for the requestHeaderNames property (in addition to STANDARD_REQUEST_HEADERS), to map all user-defined headers.

org.springframework.xmpp.XmppHeaders 类标识 DefaultXmppHeaderMapper 使用的默认头:

The org.springframework.xmpp.XmppHeaders class identifies the default headers to be used by the DefaultXmppHeaderMapper:

  • xmpp_from

  • xmpp_subject

  • xmpp_thread

  • xmpp_to

  • xmpp_type

从 4.3 版开始,您可以在头映射中通过在模式前加上 ! 来否定模式。否定模式具有优先级,因此诸如 STANDARD_REQUEST_HEADERS,thing1,thing*,!thing2,!thing3,qux,!thing1 的列表不会映射 thing1thing2thing3。该列表确实会映射标准头以及 thing4qux

Starting with version 4.3, you can negate patterns in the header mappings by preceding the pattern with !. Negated patterns get priority, so a list such as STANDARD_REQUEST_HEADERS,thing1,thing*,!thing2,!thing3,qux,!thing1 does not map thing1, thing2,or thing3. That list does map the standard headers plus thing4 and qux.

如果您有一个希望映射但以 ! 开头的用户定义的标头,您可以使用 \ 对其进行转义,如下所示:STANDARD_REQUEST_HEADERS,\!myBangHeader。在该示例中,将映射标准请求标头和 !myBangHeader

If you have a user-defined header that begins with ! that you do wish to map, can escape it with \ thus: STANDARD_REQUEST_HEADERS,\!myBangHeader. In that example, the standard request headers and !myBangHeader are mapped.

XMPP Extensions

扩展在“可扩展消息和状态协议”中添加了“可扩展性”。

Extensions put the “Extensible” in the “Extensible Messaging and Presence Protocol”.

XMPP 基于 XML,这是一种支持称为命名空间的概念的数据格式。通过命名空间,您可以在 XMPP 中添加未在原始规范中定义的内容。XMPP 规范故意只描述了一组核心功能:

XMPP is based around XML, a data format that supports a concept known as namespacing. Through namespacing, you can add bits to XMPP that are not defined in the original specifications. The XMPP specification deliberately describes only a set of core features:

  • How a client connects to a server

  • Encryption (SSL/TLS)

  • Authentication

  • How servers can communicate with each other to relay messages

  • A few other basic building blocks

一旦实现了这一点,您就拥有了一个 XMPP 客户端,并且可以发送任何类型的数据。但是,您可能需要做更多的事情。例如,您可能需要在消息中包含格式(粗体、斜体等),而这未在核心 XMPP 规范中定义。那么,您可以想办法实现这一点,但除非每个人都以您相同的方式进行操作,否则没有其他软件可以解释它(他们会忽略他们无法理解的命名空间)。

Once you have implemented this, you have an XMPP client and can send any kind of data you like. However, you may need to do more than the basics. For example, you might need to include formatting (bold, italic, and so on) in a message, which is not defined in the core XMPP specification. Well, you can make up a way to do that, but, unless everyone else does it the same way you do, no other software can interpret it (they ignore namespaces they cannot understand).

为解决该问题,XMPP 标准化基金会 (XSF) 发布了一系列称为 XMPP Extension Protocols (XEP) 的额外文档。总体而言,每个 XEP 都描述一个具体活动(从消息格式到文件传输、多用户聊天以及更多)。它们还为每个人使用该活动提供了标准格式。

To solve that problem, the XMPP Standards Foundation (XSF) publishes a series of extra documents, known as XMPP Extension Protocols (XEPs). In general, each XEP describes a particular activity (from message formatting to file transfers, multi-user chats, and many more). They also provide a standard format for everyone to use for that activity.

Smack API 使用其 extensionsexperimental projects 提供许多 XEP 实现。从 Spring Integration 版本 4.3 开始,你可以使用任何 XEP 以及现有的 XMPP 通道适配器。

The Smack API provides many XEP implementations with its extensions and experimental projects. Starting with Spring Integration version 4.3, you can use any XEP with the existing XMPP channel adapters.

为了能够处理 XEP 或任何其他自定义 XMPP 扩展,您必须提供 Smack 的 ProviderManager 预配置。您可以使用 static Java 代码进行操作,如下例所示:

To be able to process XEPs or any other custom XMPP extensions, you must provide the Smack’s ProviderManager pre-configuration. You can do so with static Java code, as the following example shows:

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

您还可以在特定实例中使用 .providers 配置文件,并使用 JVM 参数访问它,如下例所示:

You can also use a .providers configuration file in the specific instance and access it with a JVM argument, as the following example shows:

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

mycustom.providers 文件可能如下:

The mycustom.providers file might be as follows:

<?xml version="1.0"?>
<smackProviders>
<iqProvider>
    <elementName>query</elementName>
    <namespace>jabber:iq:time</namespace>
    <className>org.jivesoftware.smack.packet.Time</className>
</iqProvider>

<iqProvider>
    <elementName>query</elementName>
    <namespace>https://jabber.org/protocol/disco#items</namespace>
    <className>org.jivesoftware.smackx.provider.DiscoverItemsProvider</className>
</iqProvider>

<extensionProvider>
    <elementName>subscription</elementName>
    <namespace>https://jabber.org/protocol/pubsub</namespace>
    <className>org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider</className>
</extensionProvider>
</smackProviders>

例如,最受欢迎的 XMPP 消息传递扩展是 Google Cloud Messaging (GCM)。Smack 库为其提供了 org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider。它默认使用 experimental.providers 资源将该类注册到类路径中的 smack-experimental jar,如下面的 Maven 示例所示:

For example, the most popular XMPP messaging extension is Google Cloud Messaging (GCM). The Smack library provides org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider for that purposes. By default, it registers that class with the smack-experimental jar in the classpath by using the experimental.providers resource, as the following Maven example shows:

<!-- GCM JSON payload -->
<extensionProvider>
    <elementName>gcm</elementName>
    <namespace>google:mobile:data</namespace>
    <className>org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider</className>
</extensionProvider>

此外,GcmPacketExtension 允许目标消息传递协议解析传入数据包和构建传出数据包,如下面的示例所示:

Also, the GcmPacketExtension lets the target messaging protocol parse incoming packets and build outgoing packets, as the following examples show:

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

请参阅本章早些时候的 Inbound Message Channel AdapterOutbound Message Channel Adapter 以获取更多信息。

See Inbound Message Channel Adapter and Outbound Message Channel Adapter earlier in this chapter for more information.