如需使用最新稳定版本,请使用 Spring Integration 7.0.4spring-doc.cadn.net.cn

JMS 支持

Spring Integration 提供了用于接收和发送 JMS 消息的通道适配器。spring-doc.cadn.net.cn

您需要将以下依赖项包含到您的项目中:spring-doc.cadn.net.cn

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

The jakarta.jms:jakarta.jms-api 必须通过某些 JMS 提供商特定的实现显式添加,例如 Apache ActiveMQ。spring-doc.cadn.net.cn

实际上有两个基于 JMS 的入站通道适配器。 第一个使用 Spring 的 JmsTemplate 基于轮询周期进行接收。 第二个是“消息驱动”的,依赖于 Spring MessageListener 容器。 出站通道适配器使用 JmsTemplate 按需转换并发送 JMS 消息。spring-doc.cadn.net.cn

通过使用 JmsTemplateMessageListener 容器,Spring Integration 依赖于 Spring 的 JMS 支持。 理解这一点非常重要,因为这些适配器上暴露的大多数属性都配置了底层的 JmsTemplateMessageListener 容器。 有关 JmsTemplateMessageListener 容器的更多详细信息,请参阅 Spring JMS 文档spring-doc.cadn.net.cn

虽然 JMS 通道适配器旨在用于单向消息传递(仅发送或仅接收),但 Spring Integration 还提供了用于请求和回复操作的入站和出站 JMS 网关。 入站网关依赖于 Spring 的 MessageListener 容器实现之一来进行消息驱动接收。 它也能够将返回值发送到由接收到的消息提供的 reply-to 目的地。 出站网关向 request-destination(或 request-destination-namerequest-destination-expression)发送 JMS 消息,然后接收回复消息。 您可以显式配置 reply-destination 引用(或 reply-destination-namereply-destination-expression)。 否则,出站网关将使用 JMS 临时队列 (TemporaryQueue)spring-doc.cadn.net.cn

在 Spring Integration 2.2 之前,如有必要,会为每个请求或回复创建(并移除)一个TemporaryQueue。 从 Spring Integration 2.2 开始,您可以配置出站网关使用MessageListener容器来接收回复,而不是直接为每个请求使用新的(或缓存的)Consumer来接收回复。 如此配置后,如果没有提供显式的回复目的地,则每个网关使用单个TemporaryQueue,而不是每个请求使用一个。spring-doc.cadn.net.cn

从版本 6.0 开始,如果将 replyPubSubDomain 选项设置为 true,出站网关将创建 TemporaryTopic 而不是 TemporaryQueue。 某些 JMS 提供商对这些目标的处理方式不同。spring-doc.cadn.net.cn

入站通道适配器

入站通道适配器需要引用单个 JmsTemplate 实例,或同时引用 ConnectionFactoryDestination(您可以使用'destinationName'替代'destination'引用)。 以下示例定义了一个具有 Destination 引用的入站通道适配器:spring-doc.cadn.net.cn

@Bean
public IntegrationFlow jmsInbound(ConnectionFactory connectionFactory) {
    return IntegrationFlow.from(
                    Jms.inboundAdapter(connectionFactory)
                       .destination("inQueue"),
                    e -> e.poller(poller -> poller.fixedRate(30000)))
            .handle(m -> System.out.println(m.getPayload()))
            .get();
}
@Bean
fun jmsInbound(connectionFactory: ConnectionFactory) =
    integrationFlow(
            Jms.inboundAdapter(connectionFactory).destination("inQueue"),
            { poller { Pollers.fixedRate(30000) } })
       {
            handle { m -> println(m.payload) }
       }
@Bean
@InboundChannelAdapter(value = "exampleChannel", poller = @Poller(fixedRate = "30000"))
public MessageSource<Object> jmsIn(ConnectionFactory connectionFactory) {
    JmsDestinationPollingSource source = new JmsDestinationPollingSource(new JmsTemplate(connectionFactory));
    source.setDestinationName("inQueue");
    return source;
}
<int-jms:inbound-channel-adapter id="jmsIn" destination="inQueue" channel="exampleChannel">
    <int:poller fixed-rate="30000"/>
</int-jms:inbound-channel-adapter>
从上述配置中可以注意到,inbound-channel-adapter是一个轮询消费者。 这意味着它被触发时会调用receive()。 您应当仅在轮询频率相对较低且时效性不重要的场景中使用此方式。 对于所有其他情况(绝大多数基于JMS的使用场景),message-driven-channel-adapter后文将详细描述)是更好的选择。
默认情况下,所有需要引用 ConnectionFactory 的 JMS 适配器都会自动查找名为 jmsConnectionFactory 的 Bean。 这就是为什么在许多示例中看不到 connection-factory 属性的原因。 然而,如果您的 JMS ConnectionFactory 使用了不同的 Bean 名称,则需要提供该属性。

如果将 extract-payload 设置为 true(默认值),则接收到的 JMS 消息将通过 MessageConverter。 依赖默认 SimpleMessageConverter 时,这意味着生成的 Spring Integration 消息的负载即为 JMS 消息的负载。 JMS TextMessage 生成基于字符串的负载,JMS BytesMessage 生成字节数组负载,而 JMS ObjectMessage 的可序列化实例则成为 Spring Integration 消息的负载。 如果您希望将原始 JMS 消息作为 Spring Integration 消息的负载,请将 extractPayload 选项设置为 falsespring-doc.cadn.net.cn

从版本 5.0.8 开始,org.springframework.jms.connection.CachingConnectionFactorycacheConsumers 的默认值由 receive-timeout(表示无等待)变为 -1,否则为 1 秒。 JMS 入站通道适配器会根据提供的 ConnectionFactory 和选项创建一个基于 DynamicJmsTemplate 的组件。 如果需要外部 JmsTemplate(例如在 Spring Boot 环境中),或者未启用 ConnectionFactory 缓存,或不存在 cacheConsumers,则建议设置 jmsTemplate.receiveTimeout(-1),以便实现非阻塞消费:spring-doc.cadn.net.cn

Jms.inboundAdapter(connectionFactory)
        .destination(queueName)
        .configureJmsTemplate(template -> template.receiveTimeout(-1))

事务

从版本 4.0 开始,入站通道适配器支持 session-transacted 属性。 在早期版本中,您必须注入一个 JmsTemplate,并将 sessionTransacted 设置为 true。 (该适配器确实允许您将 acknowledge 属性设置为 transacted,但这是不正确的且无法正常工作)。spring-doc.cadn.net.cn

注意,然而将 session-transacted 设置为 true 几乎没有价值,因为在 receive() 操作之后、消息发送到 channel 之前,事务会立即提交。spring-doc.cadn.net.cn

如果您希望整个流程都是事务性的(例如,如果存在下游出站通道适配器),则必须使用带有 transactional 的轮询器,并设置 JmsTransactionManager。 或者,考虑使用 jms-message-driven-channel-adapter,并将 acknowledge 设置为 transacted(默认值)。spring-doc.cadn.net.cn

消息驱动通道适配器

The message-driven-channel-adapter 需要引用一个 Spring MessageListener 容器的实例(AbstractMessageListenerContainer 的任何子类),或者同时引用 ConnectionFactoryDestination(可以使用 'destinationName' 替代 'destination' 引用)。 以下示例定义了一个带有 Destination 引用的消息驱动通道适配器:spring-doc.cadn.net.cn

@Bean
public IntegrationFlow jmsMessageDrivenRedeliveryFlow() {
    return IntegrationFlow
            .from(Jms.messageDrivenChannelAdapter(jmsConnectionFactory())
                     .destination("inQueue"))
            .channel("exampleChannel")
            .get();
}
@Bean
fun jmsMessageDrivenFlowWithContainer() =
        integrationFlow(
                Jms.messageDrivenChannelAdapter(jmsConnectionFactory())
                             .destination("inQueue")) {
            channel("exampleChannel")
        }
@Bean
public JmsMessageDrivenEndpoint jmsIn() {
    JmsMessageDrivenEndpoint endpoint = new JmsMessageDrivenEndpoint(container(), listener());
    return endpoint;
}
@Bean
public AbstractMessageListenerContainer container() {
    DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
    container.setConnectionFactory(cf());
    container.setDestinationName("inQueue");
    return container;
}

@Bean
public ChannelPublishingJmsMessageListener listener() {
    ChannelPublishingJmsMessageListener listener = new ChannelPublishingJmsMessageListener();
    listener.setRequestChannelName("exampleChannel");
    return listener;
}
<int-jms:message-driven-channel-adapter id="jmsIn" destination="inQueue" channel="exampleChannel"/>

消息驱动适配器还接受一些与 MessageListener 容器相关的属性。 仅当您未提供 container 引用时,才会考虑这些值。 在这种情况下,将根据这些属性创建并配置一个 DefaultMessageListenerContainer 实例。 例如,您可以指定 transaction-manager 引用、concurrent-consumers 值以及若干其他属性引用和值。 有关更多详细信息,请参阅 Javadoc 和 Spring Integration 的 JMS 模式 (spring-integration-jms.xsd)。spring-doc.cadn.net.cn

如果您有一个自定义的监听器容器实现(通常是 DefaultMessageListenerContainer 的子类),您可以通过使用 container 属性提供该类的实例引用,或者通过使用 container-class 属性提供其完全限定的类名。 在这种情况下,适配器上的属性将被传递到您的自定义容器的实例中。spring-doc.cadn.net.cn

您不能使用 Spring JMS 命名空间元素 <jms:listener-container/> 来为 <int-jms:message-driven-channel-adapter> 配置容器引用,因为该元素实际上并不引用容器。 每个 <jms:listener/> 子元素都会拥有其自己的 DefaultMessageListenerContainer(共享属性在父级 <jms:listener-container/> 元素上定义)。 您可以为每个监听器子元素指定一个 id,并使用它向通道适配器注入依赖,但 <jms:/> 命名空间需要一个真实的监听器。spring-doc.cadn.net.cn

建议为<bean>配置一个常规的DefaultMessageListenerContainer,并在通道适配器中将其用作参考。spring-doc.cadn.net.cn

从版本 4.2 开始,默认 acknowledge 模式为 transacted,除非您提供了外部容器。 在这种情况下,您应根据需要配置该容器。 我们建议使用 transacted 配合 DefaultMessageListenerContainer 以避免消息丢失。

'extract-payload' 属性具有相同的效果,其默认值为'true'。 poller元素不适用于消息驱动通道适配器,因为它是被主动调用的。 对于大多数场景,消息驱动方式更好,因为一旦从底层 JMS 消费者接收到消息,它们就会被传递给MessageChannelspring-doc.cadn.net.cn

最后,<message-driven-channel-adapter>元素也接受'error-channel'属性。 这提供了与进入GatewayProxyFactoryBean中描述的基本相同的功能。 以下示例展示了如何为消息驱动通道适配器设置错误通道:spring-doc.cadn.net.cn

<int-jms:message-driven-channel-adapter id="jmsIn" destination="inQueue"
    channel="exampleChannel"
    error-channel="exampleErrorChannel"/>

将前例与稍后讨论的通用网关配置或 JMS 'inbound-gateway' 进行比较时,关键区别在于我们处于单向流程中,因为这是一个 'channel-adapter',而非网关。 因此,从 'error-channel' 向下游的流程也应是单向的。 例如,它可以发送到日志记录处理器,或者连接到不同的 JMS <outbound-channel-adapter> 元素。spring-doc.cadn.net.cn

从主题消费时,将 pub-sub-domain 属性设置为 true。 将 subscription-durable 设置为 true 以启用持久订阅,或设置为 subscription-shared 以启用共享订阅(这需要 JMS 2.0 代理,自 4.2 版本起可用)。 使用 subscription-name 来命名订阅。spring-doc.cadn.net.cn

从 5.1 版本开始,当应用仍在运行时停止端点,底层的监听容器将被关闭,从而关闭其共享连接和消费者。 此前,连接和消费者会保持打开状态。 若要恢复之前的行为,请将 shutdownContainerOnStop 上的 JmsMessageDrivenEndpoint 设置为 falsespring-doc.cadn.net.cn

从版本 6.3 开始,ChannelPublishingJmsMessageListener 现在可以配合 RetryTemplateRecoveryCallback<Message<?>> 用于下游发送以及发送并接收操作的重试。 这些选项也已暴露给 Java DSL 的 JmsMessageDrivenChannelAdapterSpecspring-doc.cadn.net.cn

入站转换错误

从版本 4.2 开始,'error-channel'(错误通道)也用于转换错误。 以前,如果 JMS <message-driven-channel-adapter/><inbound-gateway/> 由于转换错误而无法传递消息,则会向容器抛出一个异常。 如果容器配置为使用事务,则消息会被回滚并反复重投。 转换过程发生在消息构建之前和期间,因此此类错误不会被发送到 'error-channel'。 现在,此类转换异常会导致一个 ErrorMessage 被发送到 'error-channel',并将该异常作为 payload。 如果您希望事务回滚,并且已定义了 'error-channel',则 'error-channel' 上的集成流必须重新抛出该异常(或另一个异常)。 如果错误流未抛出异常,则事务将被提交,消息将被移除。 如果没有定义 'error-channel',则异常将像以前一样被抛回到容器中。spring-doc.cadn.net.cn

出站通道适配器

The JmsSendingMessageHandler 实现了 MessageHandler 接口,能够将 Spring Integration Messages 转换为 JMS 消息,然后发送到 JMS 目的地。 它需要一个 jmsTemplate 引用,或者同时需要 jmsConnectionFactorydestination 引用(destinationName 可以替代 destination)。 与入站通道适配器一样,配置此适配器的最简单方法是使用命名空间支持。 以下配置将创建一个适配器,该适配器从 exampleChannel 接收 Spring Integration 消息,将这些消息转换为 JMS 消息,并将它们发送到 bean 名称为 outQueue 的 JMS 目的地引用:spring-doc.cadn.net.cn

@Bean
public IntegrationFlow jmsOutboundFlow() {
    return IntegrationFlow.from("exampleChannel")
                .handle(Jms.outboundAdapter(cachingConnectionFactory())
                    .destinationExpression("headers." + SimpMessageHeaderAccessor.DESTINATION_HEADER)
                    .configureJmsTemplate(t -> t.id("jmsOutboundFlowTemplate")));
}
@Bean
fun jmsOutboundFlow() =
        integrationFlow("exampleChannel") {
            handle(Jms.outboundAdapter(jmsConnectionFactory())
                    .apply {
                        destinationExpression("headers." + SimpMessageHeaderAccessor.DESTINATION_HEADER)
                        deliveryModeFunction<Any> { DeliveryMode.NON_PERSISTENT }
                        timeToLiveExpression("10000")
                        configureJmsTemplate { it.explicitQosEnabled(true) }
                    }
            )
        }
@Bean
jmsOutboundFlow() {
    integrationFlow('exampleChannel') {
        handle(Jms.outboundAdapter(new ActiveMQConnectionFactory())
                .with {
                    destinationExpression 'headers.' + SimpMessageHeaderAccessor.DESTINATION_HEADER
                    deliveryModeFunction { DeliveryMode.NON_PERSISTENT }
                    timeToLiveExpression '10000'
                    configureJmsTemplate {
                        it.explicitQosEnabled true
                    }
                }
        )
    }
}
@Bean
@ServiceActivator(inputChannel = "exampleChannel")
public MessageHandler jmsOut() {
    JmsSendingMessageHandler handler = new JmsSendingMessageHandler(new JmsTemplate(connectionFactory));
    handler.setDestinationName("outQueue");
    return handler;
}
<int-jms:outbound-channel-adapter id="jmsOut" destination="outQueue" channel="exampleChannel"/>

与入站通道适配器一样,这里也有一个'extract-payload'属性。 然而,对于出站适配器,其含义是相反的。 该布尔属性并不应用于 JMS 消息,而是应用于 Spring Integration 消息的负载(payload)。 换句话说,决策在于:是将整个 Spring Integration 消息本身作为 JMS 消息体传递,还是仅将 Spring Integration 消息的负载作为 JMS 消息体传递。 默认值为'true'。 因此,如果您传入一个负载为String的 Spring Integration 消息,将会创建一个 JMS TextMessage。 另一方面,如果您希望通过 JMS 将整个实际的 Spring Integration 消息发送到另一个系统,请将其设置为'false'。spring-doc.cadn.net.cn

无论载荷提取的布尔值如何,只要您依赖默认转换器或提供对另一个 MessageConverter 实例的引用,Spring Integration 都会将 JMS 属性映射到 MessageHeaders。 (对于“入站”适配器也适用相同规则,只是在这些情况下,JMS 属性会映射到 Spring Integration MessageHeaders)。

从 5.1 版本开始,<int-jms:outbound-channel-adapter>JmsSendingMessageHandler)可以使用 deliveryModeExpressiontimeToLiveExpression 属性进行配置,以便在运行时根据请求的 Spring Message 评估 JMS 消息发送的适当 QoS 值。 DefaultJmsHeaderMapper 的新选项 setMapInboundDeliveryMode(true)setMapInboundExpiration(true) 可以作为动态 deliveryModetimeToLive 的信息源,这些信息来自消息头:spring-doc.cadn.net.cn

<int-jms:outbound-channel-adapter delivery-mode-expression="headers.jms_deliveryMode"
                        time-to-live-expression="headers.jms_expiration - T(System).currentTimeMillis()"/>

事务

从 4.0 版本开始,出站通道适配器支持 session-transacted 属性。 在早期版本中,您必须注入一个 JmsTemplate,并将 sessionTransacted 设置为 true。 该属性现在设置在内置默认 JmsTemplate 的属性上。 如果存在事务(可能来自上游 message-driven-channel-adapter),则发送操作将在同一事务内执行。 否则,将启动一个新事务。spring-doc.cadn.net.cn

传入网关

Spring Integration 的消息驱动 JMS 入站网关委托给一个 MessageListener 容器,支持动态调整并发消费者数量,并且也能处理回复消息。 该入站网关需要引用一个 ConnectionFactory 和一个请求 Destination(或'requestDestinationName')。 以下示例定义了一个 JMS inbound-gateway,它从由 bean id inQueue 引用的 JMS 队列接收消息,并将消息发送到名为 exampleChannel 的 Spring Integration 通道:spring-doc.cadn.net.cn

<int-jms:inbound-gateway id="jmsInGateway"
    request-destination="inQueue"
    request-channel="exampleChannel"/>

由于网关提供请求 - 响应行为,而非单向发送或接收行为,因此它们也具有两个用于“载荷提取”的独立属性(正如前面讨论过的通道适配器的'extract-payload'设置)。 对于入站网关,'extract-request-payload'属性决定是否提取接收到的 JMS 消息体。 如果设置为'false',则 JMS 消息本身将成为 Spring Integration 消息的载荷。 默认值为'true'。spring-doc.cadn.net.cn

同样,对于入站网关,'extract-reply-payload'属性适用于要转换为回复JMS消息的Spring Integration消息。 如果您希望传递整个Spring Integration消息(作为JMS ObjectMessage的主体),请将此值设置为'false'。 默认情况下,Spring Integration消息的有效负载也会被转换为JMS消息(例如,String有效负载会变成JMS TextMessage)。spring-doc.cadn.net.cn

与任何其他事物一样,网关调用可能会导致错误。 默认情况下,生产者不会收到在消费者端可能发生的错误通知,并会超时等待回复。 然而,有时您可能希望将错误条件传达回消费者(换句话说,您可能希望将异常视为有效回复,通过将其映射为消息)。 为了实现这一点,JMS 入站网关提供了对消息通道的支持,错误可被发送到该通道进行处理,从而可能生成符合某种契约的回复消息负载,该契约定义了调用者期望的“错误”回复内容。 您可以使用 error-channel 属性来配置此类通道,如下例所示:spring-doc.cadn.net.cn

<int-jms:inbound-gateway request-destination="requestQueue"
          request-channel="jmsInputChannel"
          error-channel="errorTransformationChannel"/>

<int:transformer input-channel="exceptionTransformationChannel"
        ref="exceptionTransformer" method="createErrorResponse"/>

您可能注意到,此示例与进入GatewayProxyFactoryBean中包含的示例非常相似。 同样的思路也适用于此处:exceptionTransformer可以是一个用于创建错误响应对象的POJO,您可以引用nullChannel来抑制这些错误,或者省略'error-channel'让异常继续传播。spring-doc.cadn.net.cn

当从主题消费时,将 pub-sub-domain 属性设置为 true。 将 subscription-durable 设置为 true 以创建持久订阅,或设置为 subscription-shared 以创建共享订阅(需要 JMS 2.0 代理,自 4.2 版本起可用)。 使用 subscription-name 来命名该订阅。spring-doc.cadn.net.cn

从 4.2 版本开始,默认模式为 transacted,除非提供了外部容器。 在这种情况下,您应根据需要配置该容器。 我们建议使用 transacted 配合 DefaultMessageListenerContainer 以避免消息丢失。

从 5.1 版本开始,当应用仍在运行时停止端点,底层的监听容器将被关闭,从而关闭其共享连接和消费者。 此前,连接和消费者会保持打开状态。 若要恢复之前的行为,请将 shutdownContainerOnStop 上的 JmsInboundGateway 设置为 falsespring-doc.cadn.net.cn

默认情况下,JmsInboundGateway会查找接收到的消息中的jakarta.jms.Message.getJMSReplyTo()属性,以确定回复的发送位置。 否则,可以配置一个静态的defaultReplyDestinationdefaultReplyQueueNamedefaultReplyTopicName。 此外,从6.1版本开始,可以在提供的ChannelPublishingJmsMessageListener上配置replyToExpression,以便在请求上的标准JMSReplyTo属性为null时动态确定回复目标。 接收到的jakarta.jms.Message用作根求值上下文对象。 以下示例演示了如何使用Java DSL API配置一个入站JMS网关,其自定义回复目标从请求消息中解析得出:spring-doc.cadn.net.cn

@Bean
public IntegrationFlow jmsInboundGatewayFlow(ConnectionFactory connectionFactory) {
    return IntegrationFlow.from(
                    Jms.inboundGateway(connectionFactory)
                            .requestDestination("requestDestination")
                            .replyToFunction(message -> message.getStringProperty("myReplyTo")))
            .<String, String>transform(String::toUpperCase)
            .get();
}

从 6.3 版本开始,Jms.inboundGateway() API 提供了用于重试内部发送和接收操作的retryTemplate()recoveryCallback()选项。spring-doc.cadn.net.cn

出站网关

出站网关从 Spring Integration 消息创建 JMS 消息,并将它们发送到 request-destination。 随后,它处理 JMS 回复消息:要么使用选择器从您配置的 reply-destination 接收,要么如果未提供 reply-destination,则创建 JMS TemporaryQueue(如果 replyPubSubDomain= true 则为 TemporaryTopic)实例。spring-doc.cadn.net.cn

reply-destination(或 reply-destination-name)与一个设置了 trueCachingConnectionFactory 一起使用可能会导致内存溢出。这是因为每个请求都会创建一个新的消费者,并带有新的选择器(基于 correlation-key 的值进行选择;如果没有 correlation-key,则基于发送的 JMSMessageID 进行选择)。由于这些选择器是唯一的,它们在当前请求完成后会保留在缓存中(未被使用)。spring-doc.cadn.net.cn

如果您指定了回复目的地,建议不要使用缓存的消费者。 或者,考虑使用 <reply-listener/> 作为 如下所述spring-doc.cadn.net.cn

以下示例展示了如何配置出站网关:spring-doc.cadn.net.cn

<int-jms:outbound-gateway id="jmsOutGateway"
    request-destination="outQueue"
    request-channel="outboundJmsRequests"
    reply-channel="jmsReplies"/>

'outbound-gateway'的负载提取属性与'inbound-gateway'的属性互为反向关系(参见前文讨论)。 这意味着'extract-request-payload'属性的值应用于被转换为JMS消息作为请求发送的Spring Integration消息。 'extract-reply-payload'属性的值应用于作为响应接收的JMS消息,随后该消息被转换为Spring Integration消息并发送至'reply-channel',如前面的配置示例所示。spring-doc.cadn.net.cn

使用一个<reply-listener/>

Spring Integration 2.2 引入了另一种处理回复的技术。 如果您在网关中添加一个 <reply-listener/> 子元素,而不是为每个回复创建消费者,则将使用一个 MessageListener 容器来接收回复并将其传递给请求线程。 这不仅提供了多项性能优势,还缓解了 前文警告 中描述的缓存消费者内存占用问题。spring-doc.cadn.net.cn

当使用一个没有reply-destination的出站网关与<reply-listener/>配合时,不是为每个请求创建TemporaryQueue,而是使用单个TemporaryQueue。 (如果到代理的连接丢失并恢复,网关将按需创建额外的TemporaryQueue)。 如果将replyPubSubDomain设置为true,从版本6.0开始,将创建TemporaryTopic代替。
spring-doc.cadn.net.cn

当使用 correlation-key 时,多个网关可以共享相同的回复目标地址,因为监听器容器为每个网关使用了唯一的选择器。spring-doc.cadn.net.cn

如果您指定了回复监听器并指定了回复目标(或回复目标名称),但未提供关联键,则网关会记录一条警告并回退到 2.2 版本之前的行为。 这是因为在这种情况下无法配置选择器。 因此,无法避免回复被发送到可能配置了相同回复目标的其他网关。spring-doc.cadn.net.cn

注意,在这种情况下,每个请求都会使用一个新的消费者,并且正如上述注意事项中所描述的那样,消费者可能会在内存中累积;因此,在这种情况下不应使用缓存的消费者。spring-doc.cadn.net.cn

以下示例展示了一个具有默认属性的回复监听器:spring-doc.cadn.net.cn

<int-jms:outbound-gateway id="jmsOutGateway"
        request-destination="outQueue"
        request-channel="outboundJmsRequests"
        reply-channel="jmsReplies">
    <int-jms:reply-listener />
</int-jms-outbound-gateway>

监听器非常轻量,在大多数情况下,您只需要一个消费者。 然而,您可以添加诸如 concurrent-consumersmax-concurrent-consumers 等属性。 有关支持属性的完整列表,请参见架构说明,同时参考 Spring JMS 文档 以了解其含义。spring-doc.cadn.net.cn

空闲回复监听器

从 4.2 版本开始,您可以根据需要启动回复监听器(并在空闲一段时间后停止它),而不是在网关的生命周期内持续运行。 如果您在应用上下文中拥有许多网关,且它们大部分时间处于空闲状态,这将非常有用。 一种典型场景是:使用 Spring Integration 和 JMS 进行分区分布的应用上下文,其中包含大量(未激活的)已分区的 Spring Batch 作业。 如果所有回复监听器都处于活动状态,JMS 代理将为每个网关维护一个活动的消费者。 通过启用空闲超时,每个消费者仅在对应的批处理作业运行时存在(并在作业完成后短暂保留一段时间)。spring-doc.cadn.net.cn

属性参考 中查看 idle-reply-listener-timeoutspring-doc.cadn.net.cn

网关回复关联

本节描述了用于回复关联的机制(确保源网关仅收到其请求的回复),具体取决于网关的配置方式。 有关此处讨论的属性完整说明,请参阅属性参考spring-doc.cadn.net.cn

以下列表描述了各种场景(数字仅用于标识,顺序无关紧要):spring-doc.cadn.net.cn

  1. 没有 reply-destination* 个属性和没有 <reply-listener>spring-doc.cadn.net.cn

    A TemporaryQueue is created for each request and deleted when the request is complete (successfully or otherwise). correlation-key is irrelevant.spring-doc.cadn.net.cn

  2. 提供了 reply-destination* 属性,但未提供 <reply-listener/>correlation-keyspring-doc.cadn.net.cn

    The JMSCorrelationID equal to the outgoing message is used as a message selector for the consumer:spring-doc.cadn.net.cn

    messageSelector = "JMSCorrelationID = '" + messageId + "'"spring-doc.cadn.net.cn

    响应系统应在回复 JMSCorrelationID 中返回入站 JMSMessageID。 这是一种常见模式,Spring Integration 的入站网关以及 Spring 的 MessageListenerAdapter(用于消息驱动的 POJO)均实现了该模式。spring-doc.cadn.net.cn

    当您使用此配置时,不应为回复使用主题。 回复可能会丢失。
  3. 提供了一个 reply-destination* 属性,未提供 <reply-listener/>,且提供了 correlation-key="JMSCorrelationID"spring-doc.cadn.net.cn

    网关生成一个唯一的关联 ID 并将其插入到 JMSCorrelationID 头部。 消息选择器为:spring-doc.cadn.net.cn

    messageSelector = "JMSCorrelationID = '" + uniqueId + "'"spring-doc.cadn.net.cn

    响应系统应在回复 JMSCorrelationID 中返回入站 JMSCorrelationID。 这是一种常见模式,Spring Integration 的入站网关以及 Spring 的 MessageListenerAdapter(用于消息驱动的 POJO)均实现了该模式。spring-doc.cadn.net.cn

  4. 提供了一个 reply-destination* 属性,未提供 <reply-listener/>,且提供了 correlation-key="myCorrelationHeader"spring-doc.cadn.net.cn

    网关生成一个唯一的相关性 ID,并将其插入到 myCorrelationHeader 消息属性中。 correlation-key 可以是任何用户定义的值。 消息选择器为:spring-doc.cadn.net.cn

    messageSelector = "myCorrelationHeader = '" + uniqueId + "'"spring-doc.cadn.net.cn

    预期响应系统在回复myCorrelationHeader中返回入站myCorrelationHeaderspring-doc.cadn.net.cn

  5. 提供一个 reply-destination* 属性,未提供 <reply-listener/>,且 correlation-key="JMSCorrelationID*" (注意相关键中的 *。)spring-doc.cadn.net.cn

    网关使用请求消息中 jms_correlationId 头部(如果存在)的值,并将其插入到 JMSCorrelationID 头部。 消息选择器为:spring-doc.cadn.net.cn

    messageSelector = "JMSCorrelationID = '" + headers['jms_correlationId'] + "'"spring-doc.cadn.net.cn

    用户必须确保此值是唯一的。spring-doc.cadn.net.cn

    如果不存在该头部,网关将表现为 3spring-doc.cadn.net.cn

    响应系统应在回复 JMSCorrelationID 中返回入站 JMSCorrelationID。 这是一种常见模式,Spring Integration 的入站网关以及 Spring 的 MessageListenerAdapter(用于消息驱动的 POJO)均实现了该模式。spring-doc.cadn.net.cn

  6. 未提供 reply-destination* 个属性,但提供了 <reply-listener>spring-doc.cadn.net.cn

    创建一个临时队列,用于该网关实例的所有回复。 消息中不需要关联数据,但发出的 JMSMessageID 在网关内部被使用,以便将回复定向到正确的请求线程。spring-doc.cadn.net.cn

  7. 提供了 reply-destination* 属性,提供了 <reply-listener>,未提供 correlation-keyspring-doc.cadn.net.cn

    配置 <reply-listener/> 将被忽略,网关行为与 2 相同。 会写入一条警告日志消息以指示此情况。spring-doc.cadn.net.cn

  8. 提供一个 reply-destination* 属性,提供一个 <reply-listener>,以及一个 correlation-key="JMSCorrelationID"spring-doc.cadn.net.cn

    网关具有唯一的关联ID,并将其插入到 JMSCorrelationID 头中(gatewayId + "_" + ++seq),同时该值递增。 消息选择器为:spring-doc.cadn.net.cn

    messageSelector = "JMSCorrelationID LIKE '" + gatewayId%'"spring-doc.cadn.net.cn

    预期响应系统将在回复 JMSCorrelationID 中返回入站 JMSCorrelationID。 这是一种常见模式,Spring Integration 的入站网关以及 Spring 的 MessageListenerAdapter(用于消息驱动的 POJO)均实现了该模式。 由于每个网关都有唯一的 ID,因此每个实例仅接收其自身的回复。 完整的关联数据用于将回复路由到正确的请求线程。spring-doc.cadn.net.cn

  9. reply-destination* 属性提供了 <reply-listener/>,并且提供了 correlation-key="myCorrelationHeader"spring-doc.cadn.net.cn

    网关具有一个唯一的关联 ID,并将其插入到 myCorrelationHeader 属性中(gatewayId + "_" + ++seq),同时附带一个递增的值。 correlation-key 可以是任何用户自定义的值。 消息选择器为:spring-doc.cadn.net.cn

    messageSelector = "myCorrelationHeader LIKE '" + gatewayId%'"spring-doc.cadn.net.cn

    响应系统预期在回复 myCorrelationHeader 中返回入站 myCorrelationHeader。 由于每个网关都有唯一的 ID,因此每个实例仅接收其自身的回复。 完整的关联数据用于将回复路由到正确的请求线程。spring-doc.cadn.net.cn

  10. 提供一个 reply-destination* 属性,提供一个 <reply-listener/>,以及一个 correlation-key="JMSCorrelationID*"spring-doc.cadn.net.cn

    (注意相关键中的 *spring-doc.cadn.net.cn

    用户提供的关联 ID 不允许与回复监听器一起使用。 网关不会使用此配置进行初始化。spring-doc.cadn.net.cn

异步网关

从 4.3 版本开始,您在配置出站网关时现在可以指定 async="true"(或在 Java 中为 setAsync(true))。spring-doc.cadn.net.cn

默认情况下,当向网关发送请求时,请求线程会挂起,直到收到响应。 随后流程在该线程上继续执行。 如果 asynctrue,则在 send() 完成后立即释放请求线程,响应将返回(且流程继续)在监听器容器线程上。 当网关在轮询线程上被调用时,这可能非常有用。 该线程被释放后,可用于框架内的其他任务。spring-doc.cadn.net.cn

Thee async requires a <reply-listener/> (or setUseReplyContainer(true) when using Java configuration). It also requires a correlationKey (usually JMSCorrelationID) to be specified. If either of these conditions are not met, async is ignored.spring-doc.cadn.net.cn

属性参考

以下列表显示了outbound-gateway的所有可用属性:spring-doc.cadn.net.cn

<int-jms:outbound-gateway
    connection-factory="connectionFactory" (1)
    correlation-key="" (2)
    delivery-persistent="" (3)
    destination-resolver="" (4)
    explicit-qos-enabled="" (5)
    extract-reply-payload="true" (6)
    extract-request-payload="true" (7)
    header-mapper="" (8)
    message-converter="" (9)
    priority="" (10)
    receive-timeout="" (11)
    reply-channel="" (12)
    reply-destination="" (13)
    reply-destination-expression="" (14)
    reply-destination-name="" (15)
    reply-pub-sub-domain="" (16)
    reply-timeout="" (17)
    request-channel="" (18)
    request-destination="" (19)
    request-destination-expression="" (20)
    request-destination-name="" (21)
    request-pub-sub-domain="" (22)
    time-to-live="" (23)
    requires-reply="" (24)
    idle-reply-listener-timeout="" (25)
    async=""> (26)
  <int-jms:reply-listener /> (27)
</int-jms:outbound-gateway>
1 jakarta.jms.ConnectionFactory 的引用。 默认值为 jmsConnectionFactory
2 包含相关数据以将响应与回复相关联的属性名称。如果未指定,网关期望响应系统在JMSCorrelationID头中返回出站JMSMessageID头的值。如果已指定,网关将生成相关 ID 并将其填充到指定的属性中。响应系统必须在相同的属性中回显该值。它可以被设置为 JMSCorrelationID,此时将使用标准头而不是 String 属性来保存关联数据。当您使用 <reply-container/> 时,如果您提供了显式的 reply-destination,则必须指定 correlation-key。从版本 4 开始。0.1, 此属性也支持值 JMSCorrelationID*,这意味着如果出站消息已经包含一个 JMSCorrelationID(从 jms_correlationId 映射而来)的头部,则使用该头部而不是生成新的头部。注意,当您使用<reply-container/>时,不允许使用JMSCorrelationID*键,因为容器需要在初始化期间设置消息选择器。
您应理解,网关无法确保唯一性,如果提供的关联ID不唯一,可能会产生意外的副作用。
3 一个布尔值,表示交付模式应为 DeliveryMode.PERSISTENT (true) 还是 DeliveryMode.NON_PERSISTENT (false)。 此设置仅在 explicit-qos-enabledtrue 时生效。
4 A DestinationResolver。 默认值为 DynamicDestinationResolver,它将目标名称映射为具有相同名称的队列或主题。
5 当设置为 true 时,它将启用服务质量属性:prioritydelivery-modetime-to-live
6 当设置为 true(默认值)时,Spring Integration 回复消息的有效载荷由 JMS 回复消息的正文创建(通过 MessageConverter 实现)。 当设置为 false 时,整个 JMS 消息成为 Spring Integration 消息的有效载荷。
7 当设置为 true(默认值)时,Spring Integration 消息的负载会被转换为 JMSMessage(通过 MessageConverter 实现)。 当设置为 false 时,整个 Spring Integration 消息会被转换为 JMSMessage。 在这两种情况下,Spring Integration 消息的头信息都会通过 HeaderMapper 映射到 JMS 头信息和属性。
8 一个 HeaderMapper 用于将 Spring Integration 消息头与 JMS 消息头和属性进行映射。
9 MessageConverter 的引用,用于在 JMS 消息和 Spring Integration 消息负载(如果 extract-request-payloadfalse,则为消息)之间进行转换。 默认值为 SimpleMessageConverter
10 请求消息的默认优先级。 如果存在消息优先级标头,则会被其覆盖。 其范围是 09。 仅当 explicit-qos-enabledtrue 时,此设置才会生效。
11 等待回复的时间(以毫秒为单位)。 默认值为 5000(五秒)。
12 回复消息发送到的频道。
13 Destination 的引用,该值被设置为 JMSReplyTo 头部。 reply-destinationreply-destination-expressionreply-destination-name 中最多只能提供一个。 如果未提供任何一项,则将使用 TemporaryQueue 作为对此网关的回复。
14 一个求值为 Destination 的 SpEL 表达式,该值将作为 JMSReplyTo 响应头进行设置。 该表达式的结果可以是一个 Destination 对象或一个 String。 它由 DestinationResolver 用于解析实际的 Destinationreply-destinationreply-destination-expressionreply-destination-name 中最多只能提供一个。 如果未提供任何项,则使用 TemporaryQueue 作为对此网关的回复。
15 作为 JMSReplyTo 头信息设置的目的地名称。 它被 DestinationResolver 用于解析实际的 Destinationreply-destinationreply-destination-expressionreply-destination-name 中最多只能指定其中一个。 如果未提供任何一项,则使用 TemporaryQueue 作为此网关的回复地址。
16 当设置为true时,表示由DestinationResolver解析的任何回复Destination都应该是Topic而不是Queue
17 网关在发送回复消息到reply-channel时等待的时间。 仅当reply-channel可以阻塞时才生效——例如一个当前已满的具有容量限制的QueueChannel。 默认值为无穷大。
18 此网关接收请求消息的通道。
19 对发送请求消息的Destination的引用。 必须指定reply-destinationreply-destination-expressionreply-destination-name中的一个。 这三个属性中只能使用其中一个。
20 一个求值为 Destination 的 SpEL 表达式,请求消息将发送至该地址。 该表达式的结果可以是一个 Destination 对象或一个 String。 它由 DestinationResolver 用于解析实际的 Destination。 必须提供 reply-destinationreply-destination-expressionreply-destination-name 中的一个属性。 您只能使用这三个属性中的一个。
21 发送请求消息的目标名称。 它被 DestinationResolver 用于解析实际的 Destinationreply-destinationreply-destination-expressionreply-destination-name 中必须指定一个。 您只能使用这三个属性中的一个。
22 当设置为true时,表示由DestinationResolver解析的任何请求Destination都应该是Topic而不是Queue
23 指定消息的生存时间。 此设置仅在 explicit-qos-enabledtrue 时生效。
24 指定此出站网关是否必须返回非空值。 默认情况下,此值为 true,当底层服务在 receive-timeout 后未返回值时,将抛出 MessageTimeoutException。 请注意,如果预期服务从不返回回复,则最好使用 <int-jms:outbound-channel-adapter/> 代替带有 requires-reply="false"<int-jms:outbound-gateway/>。 使用后者时,发送线程将被阻塞,等待 receive-timeout 期间的回复。
25 当您使用 <reply-listener /> 时,其生命周期(启动和停止)默认与网关的生命周期相匹配。 当此值大于 0 时,容器将在需要时按需启动(即发送请求时)。 只要没有收到任何请求且没有待处理的响应,容器将持续运行直到经过至少该指定的时间。 在下一个请求到来时,容器将重新启动。 停止时间是最低值,实际可能高达该值的 1.5 倍。
26 查看 异步网关
27 当包含此元素时,回复由异步 MessageListenerContainer 接收,而不是为每个回复创建消费者。 在许多情况下,这可以提高效率。

将 JMS 消息的映射消息头

JMS 消息可以包含元信息,例如 JMS API 标头和简单属性。 您可以使用 JmsHeaderMapper 将这些内容映射到 Spring Integration 消息标头,或从其中映射出来。 JMS API 标头会被传递到相应的 setter 方法(例如 setJMSReplyTo),而其他标头则会被复制到 JMS 消息的通用属性中。 JMS 出站网关默认使用 JmsHeaderMapper 的实现进行引导,它将映射标准的 JMS API 标头以及基本类型或 String 类型的消息标头。 您也可以通过入站和出站网关的 header-mapper 属性提供自定义的标头映射器。spring-doc.cadn.net.cn

许多 JMS 厂商特定的客户端不允许直接在已创建的 JMS 消息上设置 deliveryModeprioritytimeToLive 属性。 它们被视为服务质量 (QoS) 属性,因此必须传播到目标 MessageProducer.send(message, deliveryMode, priority, timeToLive) API。 出于这个原因,DefaultJmsHeaderMapper 不会将适当的 Spring Integration 头(或表达式结果)映射到上述 JMS 消息属性中。 相反,DynamicJmsTemplateJmsSendingMessageHandler 用于将请求消息中的头值传播到 MessageProducer.send() API。 要启用此功能,您必须使用配置了 explicitQosEnabled 属性的 DynamicJmsTemplate 来配置出站端点。 Spring Integration Java DSL 默认会配置一个 DynamicJmsTemplate,但仍需设置 explicitQosEnabled 属性。
自 4.0 版本起,JMSPriority 头已映射到入站消息的标准 priority 头。 此前,priority 头仅用于出站消息。 若要恢复以前的行为(即不映射入站优先级),请将 DefaultJmsHeaderMappermapInboundPriority 属性设置为 false
自 4.3 版本起,DefaultJmsHeaderMapper 通过调用其 toString() 方法将标准 correlationId 标头作为消息属性进行映射(correlationId 通常是一个 UUID,而 JMS 不支持该类型)。 在入站侧,它被映射为 String。 这与 jms_correlationId 标头无关,后者用于与 JMSCorrelationID 标头之间进行映射。 JMSCorrelationID 通常用于关联请求和响应,而 correlationId 则常用于将相关消息组合成一个组(例如在使用聚合器或重排序器时)。

从版本 5.1 开始,DefaultJmsHeaderMapper 可以配置用于映射入站 JMSDeliveryModeJMSExpiration 属性:spring-doc.cadn.net.cn

@Bean
public DefaultJmsHeaderMapper jmsHeaderMapper() {
    DefaultJmsHeaderMapper mapper = new DefaultJmsHeaderMapper();
    mapper.setMapInboundDeliveryMode(true)
    mapper.setMapInboundExpiration(true)
    return mapper;
}

这些 JMS 属性分别映射到 JmsHeaders.DELIVERY_MODEJmsHeaders.EXPIRATION Spring 消息头。spring-doc.cadn.net.cn

消息转换、编组和反编组

如果您需要转换消息,所有 JMS 适配器和网关都允许您通过设置 MessageConverter 属性来提供 message-converter。 为此,请提供一个在同一个 ApplicationContext 中可用的 MessageConverter 实例的 bean 名称。 此外,为了与编组器(marshaller)和解组器(unmarshaller)接口保持一致,Spring 提供了 MarshallingMessageConverter,您可以使用自定义的编组器和解组器对其进行配置。 以下示例展示了如何操作spring-doc.cadn.net.cn

<int-jms:inbound-gateway request-destination="requestQueue"
    request-channel="inbound-gateway-channel"
    message-converter="marshallingMessageConverter"/>

<bean id="marshallingMessageConverter"
    class="org.springframework.jms.support.converter.MarshallingMessageConverter">
    <constructor-arg>
        <bean class="org.bar.SampleMarshaller"/>
    </constructor-arg>
    <constructor-arg>
        <bean class="org.bar.SampleUnmarshaller"/>
    </constructor-arg>
</bean>
当您提供自己的 MessageConverter 实例时,它仍会被包裹在 HeaderMappingMessageConverter 内部。 这意味着 'extract-request-payload' 和 'extract-reply-payload' 属性会影响实际传递给您的转换器的对象。 HeaderMappingMessageConverter 本身会委托给目标 MessageConverter,同时还将 Spring Integration MessageHeaders 与 JMS 消息属性进行双向映射。

JMS 支持的消息通道

前面介绍的通道适配器和网关都旨在支持与外部其他系统的集成。 入站选项假设某个其他系统正在向 JMS 目的地发送 JMS 消息,而出站选项则假设某个其他系统正在从该目的地接收消息。 该系统可能是一个 Spring Integration 应用程序,也可能不是。 当然,当将 Spring Integration 消息实例作为 JMS 消息本身的主体发送时(即设置 extract-payload 的值为 false),则假设对方系统基于 Spring Integration 构建。 但这绝非强制要求。 这种灵活性正是采用基于消息的集成选项并利用“通道”抽象(在 JMS 情况下为“目的地”)所带来的好处之一。spring-doc.cadn.net.cn

有时,对于给定的 JMS 目的地,生产者和消费者都旨在作为同一应用程序的一部分,在同一个进程中运行。 你可以通过使用一对入站和出站通道适配器来实现这一点。 这种方法的缺点是,即使从概念上讲目标只是拥有一个单一的消息通道,你仍然需要两个适配器。 Spring Integration 2.0 版本开始支持一种更好的选项。 现在,在使用 JMS 命名空间时,可以定义一个单一的“通道”,如下例所示:spring-doc.cadn.net.cn

<int-jms:channel id="jmsChannel" queue="exampleQueue"/>

前例中的通道行为与主 Spring Integration 命名空间中的普通 <channel/> 元素非常相似。 它可以通过任何端点的 input-channeloutput-channel 属性进行引用。 不同之处在于,该通道由名为 exampleQueue 的 JMS Queue 实例支持。 这意味着生产端点和消费端点之间可以进行异步消息传递。 然而,与在非 JMS <channel/> 元素内添加 <queue/> 元素所创建的更简单的异步消息通道不同,这些消息并非存储在内存队列中。 相反,这些消息被封装在 JMS 消息体中,随后该通道即可利用底层 JMS 提供者的全部功能。 采用这种替代方案最常见的理由可能是利用 JMS 消息存储转发机制所提供的持久性。spring-doc.cadn.net.cn

如果配置正确,基于 JMS 的消息通道也支持事务。 换句话说,如果发送操作属于回滚的事务,则生产者实际上不会写入基于 JMS 的事务性消息通道。 同样地,如果接收该消息属于回滚的事务,则消费者也不会从通道中物理删除 JMS 消息。 请注意,在此类场景中,生产者和消费者的事务是独立的。 这与在简单的同步 <channel/> 元素(其没有 <queue/> 子元素)之间传播事务上下文的情况有显著不同。spring-doc.cadn.net.cn

由于上述示例引用了一个 JMS Queue 实例,因此它充当点对点通道。 另一方面,如果您需要发布 - 订阅行为,可以使用单独的元素并引用 JMS Topic。 以下示例展示了如何实现这一点:spring-doc.cadn.net.cn

<int-jms:publish-subscribe-channel id="jmsChannel" topic="exampleTopic"/>

对于任一类型的基于 JMS 的通道,都可以提供目标名称而不是引用,如下例所示:spring-doc.cadn.net.cn

<int-jms:channel id="jmsQueueChannel" queue-name="exampleQueueName"/>

<jms:publish-subscribe-channel id="jmsTopicChannel" topic-name="exampleTopicName"/>

在前面的示例中,目标名称由 Spring 的默认 DynamicDestinationResolver 实现解析,但您也可以提供任意 DestinationResolver 接口的实现。 此外,JMS ConnectionFactory 是通道的一个必需属性,但默认情况下,预期的 Bean 名称为 jmsConnectionFactory。 以下示例同时提供了用于解析 JMS 目标名称的自定义实例,以及针对 ConnectionFactory 的不同名称:spring-doc.cadn.net.cn

<int-jms:channel id="jmsChannel" queue-name="exampleQueueName"
    destination-resolver="customDestinationResolver"
    connection-factory="customConnectionFactory"/>

对于<publish-subscribe-channel />,将durable属性设置为true以创建持久订阅,或设置为subscription-shared以创建共享订阅(需要JMS 2.0代理,自4.2版本起可用)。 使用subscription来命名该订阅。spring-doc.cadn.net.cn

使用 JMS 消息选择器

使用 JMS 消息选择器,您可以根据 JMS 头以及 JMS 属性过滤 JMS 消息。 例如,如果您想监听自定义 JMS 头属性 myHeaderProperty 等于 something 的消息,可以指定以下表达式:spring-doc.cadn.net.cn

myHeaderProperty = 'something'

消息选择器表达式是 SQL-92 条件表达式语法的子集,并作为 Java Message Service 规范的一部分进行定义。 您可以通过以下 Spring Integration JMS 组件的 XML 命名空间配置来指定 JMS 消息 selector 属性:spring-doc.cadn.net.cn

您无法使用 JMS 消息选择器来引用消息体值。

JMS 示例

要实验这些 JMS 适配器,请查看 Spring Integration Samples Git 仓库中提供的 JMS 示例,位于 https://github.com/spring-projects/spring-integration-samples/tree/master/basic/jmsspring-doc.cadn.net.cn

该仓库包含两个示例。 一个示例提供了入站和出站通道适配器,另一个示例提供了入站和出站网关。 它们配置为与嵌入式 ActiveMQ 进程一起运行,但您可以修改每个示例的 common.xml Spring 应用程序上下文文件,以支持不同的 JMS 提供者或独立的 ActiveMQ 进程。spring-doc.cadn.net.cn

换句话说,您可以将配置拆分,使入站和出站适配器在独立的 JVM 中运行。 如果您已安装 ActiveMQ,请修改 brokerURL 文件中的 common.xml 属性以使用 tcp://localhost:61616(而不是 vm://localhost)。 这两个示例均从标准输入(stdin)接收输入,并将结果回显到标准输出(stdout)。 请查看配置以了解这些消息是如何通过 JMS 进行路由的。spring-doc.cadn.net.cn