对于最新的稳定版本,请使用 Spring Integration 6.4.0! |
XMPP 支持
Spring 集成为 XMPP 提供了通道适配器。 XMPP 代表“可扩展消息传递和在线状态协议”。
XMPP 描述了多个代理在分布式系统中相互通信的一种方式。 规范的用例是发送和接收聊天消息,尽管 XMPP 可以(并且正在)用于其他类型的应用程序。 XMPP 描述参与者网络。 在该网络中,参与者可以直接相互称呼并广播状态更改(例如“在线状态”)。
XMPP 提供的消息结构是世界上一些最大的即时消息网络的基础,包括 Google Talk(GTalk,也可从 GMail 中获得)和 Facebook Chat。 有许多优秀的开源 XMPP 服务器可用。 两种流行的实现是 Openfire 和 ejabberd。
Spring 集成通过提供 XMPP 适配器来提供对 XMPP 的支持,XMPP 适配器支持发送和接收 XMPP 聊天消息和来自客户端名册中其他条目的状态更改。
您需要将此依赖项包含在您的项目中:
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-xmpp</artifactId>
<version>6.2.11</version>
</dependency>
compile "org.springframework.integration:spring-integration-xmpp:6.2.11"
与其他适配器一样,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
<int-xmpp:xmpp-connection
id="myConnection"
user="user"
password="password"
host="host"
port="port"
resource="theNameOfTheResource"
subscription-mode="accept_all"/>
为了更加方便,您可以依赖默认命名约定并省略该属性。
缺省名称 () 用于此连接 Bean。id xmppConnection |
如果 XMPP 连接过时,只要记录了以前的连接状态(已验证),就会使用自动登录进行重新连接尝试。
我们还注册了一个 ,如果启用了日志记录级别,它会记录连接事件。ConnectionListener
DEBUG
该属性启动 roster 侦听器以处理来自其他用户的传入订阅。
此功能并不总是可用于目标 XMPP 服务器。
例如,Google Cloud Messaging (GCM) 和 Firebase Cloud Messaging (FCM) 完全禁用了它。
要关闭订阅的名册侦听器,您可以在使用 XML 配置 () 时使用空字符串或在使用 Java 配置时使用空字符串对其进行配置。
这样做也会在登录阶段禁用名单。
有关更多信息,请参阅 Roster.setRosterLoadedAtLogin(boolean)。
subscription-mode
subscription-mode=""
XmppConnectionFactoryBean.setSubscriptionMode(null)
XMPP 消息
Spring 集成支持发送和接收 XMPP 消息。 为了接收它们,它提供了一个入站消息通道适配器。 为了发送它们,它提供了一个出站消息通道适配器。
入站消息通道适配器
Spring 集成适配器支持接收来自系统中其他用户的聊天消息。
为此,入站消息通道适配器代表您以用户身份“登录”,并接收发送给该用户的消息。
然后,这些消息被转发到你的 Spring 集成客户端。
该元素为 XMPP 入站消息通道适配器提供 Configuration 支持。
以下示例显示如何配置它:inbound-channel-adapter
<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 连接的引用。
XMPP 入站适配器是事件驱动的,是一种实施。
启动时,它会注册一个侦听传入的 XMPP 聊天消息。
它将收到的任何消息转发到底层适配器,底层适配器将它们转换为 Spring Integration 消息并将它们发送到指定的 .
停止后,它会取消注册 .Lifecycle
PacketListener
channel
PacketListener
从版本 4.3 开始,(及其 )支持在提供的 a 上注册 a 以及内部实现。
有关更多信息,请参阅 Javadoc。ChatMessageListeningEndpoint
<int-xmpp:inbound-channel-adapter>
org.jivesoftware.smack.filter.StanzaFilter
XMPPConnection
StanzaListener
版本 4.3 引入了 .
incoming 表示 evaluation 上下文的根对象。
当您使用 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
<int-xmpp:outbound-channel-adapter id="outboundEventAdapter"
channel="outboundEventChannel"
xmpp-connection="testConnection"/>
适配器期望其 input (至少) 是 type 的 payload 和 header 值,该值指定应将消息发送到哪个用户。
要创建消息,您可以使用类似于以下内容的 Java 代码:java.lang.String
XmppHeaders.CHAT_TO
Message<String> xmppOutboundMsg = MessageBuilder.withPayload("Hello, XMPP!" )
.setHeader(XmppHeaders.CHAT_TO, "userhandle")
.build();
您还可以使用 XMPP header-enricher 支持来设置标头,如下例所示:
<int-xmpp:header-enricher input-channel="input" output-channel="output">
<int-xmpp:chat-to value="[email protected]"/>
</int-xmpp:header-enricher>
从版本 4.3 开始,数据包扩展支持已添加到 (在 XML 配置中)。
除了 regular 和 payload 之外,现在您还可以发送有效负载为 (填充到 ) 而不是 的消息。
为方便起见,我们为 .
它允许您 inject ,从而在运行时针对有效负载构建一个 。
在这种情况下,负载必须是 JSON 或 XML 格式的字符串,具体取决于 XEP 协议。ChatMessageSendingMessageHandler
<int-xmpp:outbound-channel-adapter>
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 Integration 的 “presence” 适配器。
入站在线状态消息通道适配器
Spring 集成提供了一个入站在线消息通道适配器,它支持从系统中名册上的其他用户接收在线状态事件。
为此,适配器代表您以用户身份“登录”,注册 ,并将收到的在线状态更新事件作为消息转发到由属性标识的通道。
消息的有效负载是一个对象(请参阅 www.igniterealtime.org/builds/smack/docs/latest/javadoc/org/jivesoftware/smack/packet/Presence.html)。RosterListener
channel
org.jivesoftware.smack.packet.Presence
该元素为 XMPP 入站在线状态消息通道适配器提供配置支持。
以下示例配置入站状态消息通道适配器:presence-inbound-channel-adapter
<int-xmpp:presence-inbound-channel-adapter channel="outChannel"
xmpp-connection="testConnection" auto-startup="false"/>
除了通常的属性外,此适配器还需要对 XMPP 连接的引用。
此适配器是事件驱动的,是一个实现。
它在启动时注册 a,并在 stopped 时取消注册。Lifecycle
RosterListener
RosterListener
出站在线状态消息通道适配器
Spring 集成还支持发送在线状态事件,以便网络中恰好有您的其他用户看到。
当您将消息发送到出站状态消息通道适配器时,它会提取有效负载(预期为 type )并将其发送到 XMPP 连接,从而将您的状态事件通告到网络的其余部分。org.jivesoftware.smack.packet.Presence
该元素为 XMPP 出站在线消息通道适配器提供配置支持。
以下示例说明如何配置出站在线状态消息通道适配器:presence-outbound-channel-adapter
<int-xmpp:presence-outbound-channel-adapter id="eventOutboundPresenceChannel"
xmpp-connection="testConnection"/>
它也可以是轮询使用者(如果它从可轮询通道接收消息),在这种情况下,你需要注册一个 Poller。 以下示例显示了如何执行此操作:
<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 连接的引用。
如果您依赖于 XMPP 连接 Bean 的默认命名约定(如前所述),并且在应用程序上下文中只配置了一个 XMPP 连接 Bean,则可以省略该属性。
在这种情况下,将找到具有 named 的 bean 并将其注入到适配器中。xmpp-connection xmppConnection |
高级配置
Spring 集成的 XMPP 支持基于 Smack 4.0 API (www.igniterealtime.org/projects/smack/),它允许对 XMPP Connection 对象进行更复杂的配置。
如前所述,命名空间支持旨在简化基本连接配置,并且仅支持一些常见的配置属性。
但是,该对象定义了大约 20 个属性,并且为所有属性添加命名空间支持没有实际价值。
因此,对于更复杂的连接配置,您可以将 our 的实例配置为常规 bean,并将 a 作为构造函数参数注入到该 bean 中。
您可以直接在该实例上指定所需的每个属性。
(具有 'p' 名称空间的 bean 定义将很好地工作。
这样,您可以直接设置 SSL(或任何其他属性)。
以下示例显示了如何执行此操作:xmpp-connection
org.jivesoftware.smack.ConnectionConfiguration
XmppConnectionFactoryBean
org.jivesoftware.smack.ConnectionConfiguration
FactoryBean
ConnectionConfiguration
<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 机制),您可能需要执行某些静态初始值设定项。
其中一个静态初始值设定项是 ,它允许您注册支持的 SASL 机制。
对于该级别的复杂性,我们建议对 XMPP 连接配置使用 Spring Java 配置。
这样,您可以通过 Java 代码配置整个组件,并在适当的时间执行所有其他必要的 Java 代码,包括静态初始值设定项。
以下示例说明如何在 Java 中配置具有 SASL(简单身份验证和安全层)的 XMPP 连接:SASLAuthentication
@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 参考手册中的以下部分。
XMPP 消息报头
Spring 集成 XMPP 适配器会自动映射标准 XMPP 属性。
默认情况下,这些属性通过使用DefaultXmppHeaderMapper
复制到 Spring 集成或从 Spring 集成复制。MessageHeaders
任何用户定义的报头都不会复制到 XMPP 消息或从 XMPP 消息中复制,除非由 或 的属性明确指定。requestHeaderNames
replyHeaderNames
DefaultXmppHeaderMapper
映射用户定义的标头时,值还可以包含简单的通配符模式(例如 “thing*” 或 “*thing”)。 |
从版本 4.1 开始,(a superclass of ) 允许您为属性(除了 )配置令牌,以映射所有用户定义的 Headers。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 开始,您可以通过在模式前面加上 .
否定模式获得优先级,因此 does not map 、 ,或 .
该列表确实映射了标准标头 plus 和 .!
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 通过其 和 projects 提供了许多 XEP 实现。
从 Spring 集成版本 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
<?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 库为此提供了。
默认情况下,它使用资源将该类注册到 Classpath 中的 jar 中,如下面的 Maven 示例所示:org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider
smack-experimental
experimental.providers
<!-- GCM JSON payload -->
<extensionProvider>
<elementName>gcm</elementName>
<namespace>google:mobile:data</namespace>
<className>org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider</className>
</extensionProvider>
此外,还允许目标消息传送协议解析传入数据包并构建传出数据包,如下例所示:GcmPacketExtension
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 Adapter 和 Outbound Message Channel Adapter。