Spring Integration 提供了用于接收和发送 JMS 消息的通道适配器。Spring中文文档

您需要将此依赖项包含在项目中:Spring中文文档

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

必须通过某些特定于 JMS 供应商的实现(例如 Apache ActiveMQ)显式添加。jakarta.jms:jakarta.jms-apiSpring中文文档

实际上有两个基于 JMS 的入站通道适配器。 第一个使用 Spring 根据轮询周期进行接收。 第二种是“消息驱动”,依赖于 Spring 容器。 出站通道适配器使用 按需转换和发送 JMS 消息。JmsTemplateMessageListenerJmsTemplateSpring中文文档

通过使用 和 容器,Spring Integration 依赖于 Spring 的 JMS 支持。 理解这一点很重要,因为这些适配器上公开的大多数属性都配置基础和容器。 有关容器和容器的更多详细信息,请参阅 Spring JMS 文档JmsTemplateMessageListenerJmsTemplateMessageListenerJmsTemplateMessageListenerSpring中文文档

虽然 JMS 通道适配器用于单向消息传递(仅发送或仅接收),但 Spring Integration 还为请求和应答操作提供了入站和出站 JMS 网关。 入站网关依赖于 Spring 的一个容器实现来实现消息驱动的接收。 它还能够向接收到的消息提供的目标发送返回值。 出站网关向 (或 或 ) 发送 JMS 消息,然后接收回复消息。 您可以显式配置引用(或 或 )。 否则,出站网关将使用 JMS TemporaryQueueMessageListenerreply-torequest-destinationrequest-destination-namerequest-destination-expressionreply-destinationreply-destination-namereply-destination-expressionSpring中文文档

在 Spring Integration 2.2 之前,如有必要,会为每个请求或回复创建(并删除)一个。 从 Spring Integration 2.2 开始,您可以将出站网关配置为使用容器来接收回复,而不是直接使用新的(或缓存的)来接收每个请求的回复。 如果这样配置,并且没有提供显式应答目标,则每个网关都使用一个网关,而不是每个请求一个。TemporaryQueueMessageListenerConsumerTemporaryQueueSpring中文文档

从版本 6.0 开始,出站网关将创建一个 instead of if 选项设置为 。 一些 JMS 供应商以不同的方式处理这些目标。TemporaryTopicTemporaryQueuereplyPubSubDomaintrueSpring中文文档

入站通道适配器

入站通道适配器需要对单个实例的引用,或者同时需要对 a 和 a 的引用(可以提供“destinationName”来代替“destination”引用)。 以下示例使用引用定义入站通道适配器:JmsTemplateConnectionFactoryDestinationDestinationSpring中文文档

@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>
请注意,从前面的配置中可以看出,这是一个轮询使用者。 这意味着它在触发时会调用。 您应该只在轮询相对不频繁且及时性不重要的情况下才使用此功能。 对于所有其他情况(绝大多数基于 JMS 的用例),(稍后描述)是更好的选择。inbound-channel-adapterreceive()message-driven-channel-adapter
缺省情况下,所有需要引用 的 JMS 适配器都会自动查找名为 的 Bean。 这就是为什么在许多示例中看不到属性的原因。 但是,如果 JMS 具有不同的 Bean 名称,则需要提供该属性。ConnectionFactoryjmsConnectionFactoryconnection-factoryConnectionFactory

如果设置为(缺省值),则接收到的 JMS 消息将通过 . 当依赖默认值时,这意味着生成的 Spring Integration Message 将 JMS 消息的正文作为其有效负载。 JMS 生成基于字符串的有效负载,JMS 生成字节数组有效负载,JMS 的可序列化实例成为 Spring Integration 消息的有效负载。 如果您希望将原始 JMS 消息作为 Spring Integration 消息的有效负载,请将选项设置为 。extract-payloadtrueMessageConverterSimpleMessageConverterTextMessageBytesMessageObjectMessageextractPayloadfalseSpring中文文档

从版本 5.0.8 开始,和 的默认值为 (无需等待),否则为 1 秒。 JMS 入站通道适配器根据提供的 和 选项进行板条箱。 如果需要外部(例如在 Spring Boot 环境中),或者没有缓存,或者没有,建议设置是否需要非阻塞消耗:receive-timeout-1org.springframework.jms.connection.CachingConnectionFactorycacheConsumersDynamicJmsTemplateConnectionFactoryJmsTemplateConnectionFactorycacheConsumersjmsTemplate.receiveTimeout(-1)Spring中文文档

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

交易

从版本 4.0 开始,入站通道适配器支持该属性。 在早期版本中,您必须注入 set 为 的 。 (适配器确实允许您将属性设置为 ,但这是不正确的,不起作用)。session-transactedJmsTemplatesessionTransactedtrueacknowledgetransactedSpring中文文档

但是请注意,设置为 几乎没有价值,因为事务已提交 在操作之后,在将消息发送到 .session-transactedtruereceive()channelSpring中文文档

如果希望整个流是事务性的(例如,如果存在下游出站通道适配器),则必须使用带有 . 或者,考虑使用 设置为 (默认值) 的 。transactionalJmsTransactionManagerjms-message-driven-channel-adapteracknowledgetransactedSpring中文文档

请注意,从前面的配置中可以看出,这是一个轮询使用者。 这意味着它在触发时会调用。 您应该只在轮询相对不频繁且及时性不重要的情况下才使用此功能。 对于所有其他情况(绝大多数基于 JMS 的用例),(稍后描述)是更好的选择。inbound-channel-adapterreceive()message-driven-channel-adapter
缺省情况下,所有需要引用 的 JMS 适配器都会自动查找名为 的 Bean。 这就是为什么在许多示例中看不到属性的原因。 但是,如果 JMS 具有不同的 Bean 名称,则需要提供该属性。ConnectionFactoryjmsConnectionFactoryconnection-factoryConnectionFactory

消息驱动通道适配器

需要对 Spring 容器实例的引用(任何子类 ),或者两者兼而有之(可以提供“destinationName”来代替“destination”引用)。 下面的示例使用引用定义消息驱动的通道适配器:message-driven-channel-adapterMessageListenerAbstractMessageListenerContainerConnectionFactoryDestinationDestinationSpring中文文档

@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"/>

消息驱动的适配器还接受与容器相关的多个属性。 仅当未提供引用时,才会考虑这些值。 在这种情况下,将基于这些属性创建和配置 的实例。 例如,可以指定引用、值以及几个其他属性引用和值。 有关更多详细信息,请参阅 Javadoc 和 Spring Integration 的 JMS 模式 ()。MessageListenercontainerDefaultMessageListenerContainertransaction-managerconcurrent-consumersspring-integration-jms.xsdSpring中文文档

如果您有一个自定义侦听器容器实现(通常是 的子类),则可以使用该属性提供对其实例的引用,也可以使用该属性提供其完全限定的类名。 在这种情况下,适配器上的属性将传输到自定义容器的实例。DefaultMessageListenerContainercontainercontainer-classSpring中文文档

您不能使用 Spring JMS 命名空间元素来配置容器引用,因为该元素实际上并不引用容器。 每个子元素都有自己的子元素(在父元素上定义了共享属性)。 您可以为每个侦听器子元素提供一个 ,并使用它来注入通道适配器,但是,命名空间需要一个真正的侦听器。<jms:listener-container/><int-jms:message-driven-channel-adapter><jms:listener/>DefaultMessageListenerContainer<jms:listener-container/>id<jms:/>Spring中文文档

建议为 配置常规,并将其用作通道适配器中的引用。<bean>DefaultMessageListenerContainerSpring中文文档

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

“extract-payload”属性具有相同的效果,其默认值为“true”。 该元素不适用于消息驱动的通道适配器,因为它是主动调用的。 对于大多数方案,消息驱动方法更好,因为消息在从底层 JMS 使用者接收到消息后立即传递给 。pollerMessageChannelSpring中文文档

最后,该元素还接受“error-channel”属性。 这提供了相同的基本功能,如进入 GatewayProxyFactoryBean 中所述。 下面的示例演示如何在消息驱动的通道适配器上设置错误通道:<message-driven-channel-adapter>Spring中文文档

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

将前面的示例与我们稍后讨论的通用网关配置或 JMS“入站网关”进行比较时,主要区别在于我们处于单向流中,因为这是一个“通道适配器”,而不是网关。 因此,“错误通道”的下游流动也应该是单向的。 例如,它可以发送到日志记录处理程序,也可以连接到其他 JMS 元素。<outbound-channel-adapter>Spring中文文档

从主题使用时,将属性设置为 true。 对于持久预订或共享预订(需要 JMS 2.0 代理,并且从 V4.2 开始可用),设置为。 用于命名订阅。pub-sub-domainsubscription-durabletruesubscription-sharedsubscription-nameSpring中文文档

从 V5.1 开始,当端点在应用程序保持运行状态时停止时,基础侦听器容器将关闭,从而关闭其共享连接和使用者。 以前,连接和消费者保持打开状态。 若要恢复到上一个行为,请将 on 设置为 。shutdownContainerOnStopJmsMessageDrivenEndpointfalseSpring中文文档

从版本 6.3 开始,现在可以在下游发送和发送和接收操作上提供 and for 重试。 这些选项也公开到 Java DSL 中。ChannelPublishingJmsMessageListenerRetryTemplateRecoveryCallback<Message<?>>JmsMessageDrivenChannelAdapterSpecSpring中文文档

入站转换错误

从版本 4.2 开始,“error-channel”也用于转换错误。 以前,如果 JMS 或由于转换错误而无法传递消息,则会将异常抛回容器。 如果容器配置为使用事务,则会反复回滚并重新传递消息。 转换过程发生在消息构造之前和期间,因此此类错误不会发送到“错误通道”。 现在,此类转换异常会导致被发送到“错误通道”,例外情况为 . 如果您希望事务回滚,并且您定义了“错误通道”,则“错误通道”上的集成流必须重新抛出异常(或其他异常)。 如果错误流未引发异常,则提交事务并删除消息。 如果未定义“error-channel”,则异常将像以前一样扔回容器。<message-driven-channel-adapter/><inbound-gateway/>ErrorMessagepayloadSpring中文文档

消息驱动的适配器还接受与容器相关的多个属性。 仅当未提供引用时,才会考虑这些值。 在这种情况下,将基于这些属性创建和配置 的实例。 例如,可以指定引用、值以及几个其他属性引用和值。 有关更多详细信息,请参阅 Javadoc 和 Spring Integration 的 JMS 模式 ()。MessageListenercontainerDefaultMessageListenerContainertransaction-managerconcurrent-consumersspring-integration-jms.xsdSpring中文文档

如果您有一个自定义侦听器容器实现(通常是 的子类),则可以使用该属性提供对其实例的引用,也可以使用该属性提供其完全限定的类名。 在这种情况下,适配器上的属性将传输到自定义容器的实例。DefaultMessageListenerContainercontainercontainer-classSpring中文文档

您不能使用 Spring JMS 命名空间元素来配置容器引用,因为该元素实际上并不引用容器。 每个子元素都有自己的子元素(在父元素上定义了共享属性)。 您可以为每个侦听器子元素提供一个 ,并使用它来注入通道适配器,但是,命名空间需要一个真正的侦听器。<jms:listener-container/><int-jms:message-driven-channel-adapter><jms:listener/>DefaultMessageListenerContainer<jms:listener-container/>id<jms:/>Spring中文文档

建议为 配置常规,并将其用作通道适配器中的引用。<bean>DefaultMessageListenerContainerSpring中文文档

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

出站通道适配器

该接口实现,能够将Spring Integration转换为JMS消息,然后发送到JMS目标。 它需要一个引用或两个引用,并且引用(可以代替 提供)。 与入站通道适配器一样,配置此适配器的最简单方法是使用命名空间支持。 以下配置生成一个适配器,该适配器接收来自 的 Spring Integration 消息,将这些消息转换为 JMS 消息,并将它们发送到 Bean 名称为 的 JMS 目标引用:JmsSendingMessageHandlerMessageHandlerMessagesjmsTemplatejmsConnectionFactorydestinationdestinationNamedestinationexampleChanneloutQueueSpring中文文档

@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"/>

与入站通道适配器一样,有一个“提取有效负载”属性。 但是,对于出站适配器,含义是相反的。 布尔属性不应用于 JMS 消息,而是应用于 Spring Integration 消息有效负载。 换言之,决定是将 Spring Integration 消息本身作为 JMS 消息正文传递,还是将 Spring Integration 消息有效负载作为 JMS 消息正文传递。 默认值为“true”。 因此,如果传递有效负载为 的 Spring Integration 消息,则会创建一个 JMS。 另一方面,如果要通过 JMS 将实际的 Spring Integration 消息发送到另一个系统,请将其设置为 'false'。StringTextMessageSpring中文文档

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

从 V5.1 开始,可以使用 和 属性配置 () 来评估 JMS 消息的适当 QoS 值,以便在运行时针对请求 Spring 发送。 新的和选项可能有助于作为动态和消息标头的信息源:<int-jms:outbound-channel-adapter>JmsSendingMessageHandlerdeliveryModeExpressiontimeToLiveExpressionMessagesetMapInboundDeliveryMode(true)setMapInboundExpiration(true)DefaultJmsHeaderMapperdeliveryModetimeToLiveSpring中文文档

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

交易

从版本 4.0 开始,出站通道适配器支持该属性。 在早期版本中,您必须注入 set 为 的 。 该属性现在将属性设置为内置默认值。 如果存在事务(可能来自上游),则发送操作将在同一事务中执行。 否则,将启动新事务。session-transactedJmsTemplatesessionTransactedtrueJmsTemplatemessage-driven-channel-adapterSpring中文文档

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

入站网关

Spring Integration 的消息驱动的 JMS 入站网关委托给容器,支持动态调整并发使用者,还可以处理回复。 入站网关需要引用 a 和 请求 (或 'requestDestinationName') 。 以下示例定义了一个 JMS,该 JMS 从 Bean ID 引用的 JMS 队列接收,并发送到名为 :MessageListenerConnectionFactoryDestinationinbound-gatewayinQueueexampleChannelSpring中文文档

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

由于网关提供请求-应答行为而不是单向发送或接收行为,因此它们还具有两个不同的“有效负载提取”属性(如前面针对通道适配器的“提取-有效负载”设置所讨论的)。 对于入站网关,“extract-request-payload”属性确定是否提取收到的 JMS 消息正文。 如果为 'false',则 JMS 消息本身将成为 Spring Integration 消息有效负载。 默认值为“true”。Spring中文文档

同样,对于入站网关,“extract-reply-payload”属性适用于要转换为回复 JMS 消息的 Spring Integration 消息。 如果要传递整个Spring Integration消息(作为JMS ObjectMessage的主体),请将值this设置为'false'。 默认情况下,Spring Integration 消息有效负载转换为 JMS 消息也是“正确的”(例如,有效负载成为 JMS TextMessage)。StringSpring中文文档

与其他任何操作一样,网关调用可能会导致错误。 默认情况下,生产者不会收到消费者端可能发生的错误的通知,并且会超时等待回复。 但是,有时您可能希望将错误条件传达回给使用者(换句话说,您可能希望通过将异常映射到消息来将其视为有效回复)。 为了实现这一点,JMS 入站网关提供了对消息通道的支持,可以将错误发送到该通道进行处理,这可能会导致应答消息有效负载符合某些协定,该协定定义了调用方可能期望的“错误”应答。 可以使用 error-channel 属性来配置此类通道,如以下示例所示:Spring中文文档

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

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

您可能会注意到,此示例看起来与 Enter the GatewayProxyFactoryBean 中包含的示例非常相似。 同样的想法也适用于这里:可以是创建错误响应对象的 POJO,您可以引用 来抑制错误,或者您可以省略“error-channel”以让异常传播。exceptionTransformernullChannelSpring中文文档

从主题使用时,将属性设置为 true。 设置为持久订阅或共享订阅(需要 JMS 2.0 代理,并且自 V4.2 起可用)。 用于命名订阅。pub-sub-domainsubscription-durabletruesubscription-sharedsubscription-nameSpring中文文档

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

从 V5.1 开始,当端点在应用程序保持运行状态时停止时,基础侦听器容器将关闭,从而关闭其共享连接和使用者。 以前,连接和消费者保持打开状态。 若要恢复到上一个行为,请将 on 设置为 。shutdownContainerOnStopJmsInboundGatewayfalseSpring中文文档

默认情况下,在收到的消息中查找属性以确定将回复发送到何处。 否则,可以使用静态 或 或 配置。 此外,从 V6.1 开始,如果请求上有标准属性,则可以在 provided 上配置 a 以动态确定应答目标。 接收到的用于根评估上下文对象。 以下示例演示如何使用 Java DSL API 配置具有从请求消息解析的自定义应答目标的入站 JMS 网关:JmsInboundGatewayjakarta.jms.Message.getJMSReplyTo()defaultReplyDestinationdefaultReplyQueueNamedefaultReplyTopicNamereplyToExpressionChannelPublishingJmsMessageListenerJMSReplyTonulljakarta.jms.MessageSpring中文文档

@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 开始,API 公开了用于重试内部发送和接收操作的 和 选项。Jms.inboundGateway()retryTemplate()recoveryCallback()Spring中文文档

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

出站网关

出站网关从 Spring Integration 消息创建 JMS 消息,并将它们发送到 . 然后,它通过使用选择器从您配置的实例接收,或者(如果未提供)通过创建 JMS(或 if )实例来处理 JMS 回复消息。request-destinationreply-destinationreply-destinationTemporaryQueueTemporaryTopicreplyPubSubDomain= trueSpring中文文档

将 (或 ) 与 cacheConsumers 设置为的 一起使用可能会导致内存不足情况。 这是因为每个请求都会使用新的选择器获取新的使用者(在发送的 JMSMessageID 上选择值或当没有时选择)。 鉴于这些选择器是唯一的,因此在当前请求完成后,它们将保留在缓存中(未使用)。reply-destinationreply-destination-nameCachingConnectionFactorytruecorrelation-keycorrelation-keySpring中文文档

如果指定了应答目标,建议不要使用缓存的使用者。 或者,考虑使用如下所述<reply-listener/>Spring中文文档

以下示例演示如何配置出站网关:Spring中文文档

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

“outbound-gateway”有效负载提取属性与“inbound-gateway”的属性成反比(请参阅前面的讨论)。 这意味着“extract-request-payload”属性值适用于将 Spring Integration 消息转换为要作为请求发送的 JMS 消息。 'extract-reply-payload' 属性值适用于作为回复接收的 JMS 消息,然后转换为 Spring Integration 消息,随后发送到 'reply-channel',如前面的配置示例所示。Spring中文文档

使用<reply-listener/>

Spring Integration 2.2 引入了一种处理回复的替代技术。 如果将子元素添加到网关,而不是为每个回复创建使用者,则使用容器来接收回复并将其移交给请求线程。 这提供了许多性能优势,并缓解了前面警告中描述的缓存使用者内存利用率问题。<reply-listener/>MessageListenerSpring中文文档

当将 a 与没有 的出站网关一起使用时,将使用单个请求,而不是为每个请求创建一个。 (如果与代理的连接丢失并恢复,网关会根据需要创建额外的 )。 如果设置为 ,从版本 6.0 开始,则改为创建一个。<reply-listener/>reply-destinationTemporaryQueueTemporaryQueueTemporaryQueuereplyPubSubDomaintrueTemporaryTopicSpring中文文档

使用 时,多个网关可以共享相同的应答目标,因为侦听器容器使用每个网关唯一的选择器。correlation-keySpring中文文档

如果指定应答侦听器并指定应答目标(或应答目标名称),但未提供相关键,则网关将记录警告并回退到 V2.2 之前的行为。 这是因为在这种情况下无法配置选择器。 因此,无法避免应答转到可能配置了相同应答目标的不同网关。Spring中文文档

请注意,在这种情况下,每个请求都会使用一个新的使用者,并且使用者可以按照上述警告中的描述在内存中建立;因此,在这种情况下不应使用缓存的使用者。Spring中文文档

以下示例显示了具有默认属性的回复侦听器:Spring中文文档

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

侦听器非常轻量级,我们预计在大多数情况下,您只需要一个使用者。 但是,您可以添加 、 等属性。 有关支持属性的完整列表,请参阅架构,以及 Spring JMS 文档以了解它们的含义。concurrent-consumersmax-concurrent-consumersSpring中文文档

空闲回复侦听器

从版本 4.2 开始,您可以根据需要启动应答侦听器(并在空闲时间后停止它),而不是在网关的生命周期内运行。 如果应用程序上下文中有许多网关,而这些网关大多处于空闲状态,则此功能非常有用。 其中一种情况是,有许多(非活动的)分区的Spring Batch作业使用Spring Integration和JMS进行分区分发。 如果所有应答侦听器都处于活动状态,那么 JMS 代理对每个网关都有一个活动使用者。 通过启用空闲超时,每个使用者仅在相应的批处理作业运行时(以及完成后的短时间内)存在。Spring中文文档

请参见属性参考idle-reply-listener-timeoutSpring中文文档

网关回复关联

本节介绍用于回复关联的机制(确保原始网关仅接收对其请求的回复),具体取决于网关的配置方式。 有关此处讨论的属性的完整描述,请参阅属性参考Spring中文文档

以下列表描述了各种方案(数字用于识别 - 顺序无关紧要):Spring中文文档

  1. 没有属性,也没有reply-destination*<reply-listener>Spring中文文档

    为每个请求创建一个 A,并在请求完成(成功或失败)时删除。 无关紧要。TemporaryQueuecorrelation-keySpring中文文档

  2. 提供属性,但既不提供属性也不提供属性reply-destination*<reply-listener/>correlation-keySpring中文文档

    等于传出的消息用作使用者的消息选择器:JMSCorrelationIDSpring中文文档

    messageSelector = "JMSCorrelationID = '" + messageId + "'"Spring中文文档

    应答系统应在应答中返回入站。 这是一种常见的模式,由 Spring Integration 入站网关以及用于消息驱动的 POJO 的 Spring 实现。JMSMessageIDJMSCorrelationIDMessageListenerAdapterSpring中文文档

    使用此配置时,不应使用主题进行回复。 答复可能会丢失。
  3. 提供属性,不提供属性,并且reply-destination*<reply-listener/>correlation-key="JMSCorrelationID"Spring中文文档

    网关生成唯一的关联 IS 并将其插入到标头中。 消息选择器为:JMSCorrelationIDSpring中文文档

    messageSelector = "JMSCorrelationID = '" + uniqueId + "'"Spring中文文档

    应答系统应在应答中返回入站。 这是一种常见的模式,由 Spring Integration 入站网关以及用于消息驱动的 POJO 的 Spring 实现。JMSCorrelationIDJMSCorrelationIDMessageListenerAdapterSpring中文文档

  4. 提供属性,不提供属性,并且reply-destination*<reply-listener/>correlation-key="myCorrelationHeader"Spring中文文档

    网关生成唯一的相关 ID,并将其插入到 message 属性中。 可以是任何用户定义的值。 消息选择器为:myCorrelationHeadercorrelation-keySpring中文文档

    messageSelector = "myCorrelationHeader = '" + uniqueId + "'"Spring中文文档

    应答系统应在应答中返回入站。myCorrelationHeadermyCorrelationHeaderSpring中文文档

  5. 提供了属性,未提供属性,并且(请注意相关键中的属性。reply-destination*<reply-listener/>correlation-key="JMSCorrelationID*"*Spring中文文档

    网关使用请求消息中标头中的值(如果存在),并将其插入到标头中。 消息选择器为:jms_correlationIdJMSCorrelationIDSpring中文文档

    messageSelector = "JMSCorrelationID = '" + headers['jms_correlationId'] + "'"Spring中文文档

    用户必须确保此值是唯一的。Spring中文文档

    如果标头不存在,则网关的行为与 中 相同。3Spring中文文档

    应答系统应在应答中返回入站。 这是一种常见的模式,由 Spring Integration 入站网关以及用于消息驱动的 POJO 的 Spring 实现。JMSCorrelationIDJMSCorrelationIDMessageListenerAdapterSpring中文文档

  6. 未提供任何属性,只提供reply-destination*<reply-listener>Spring中文文档

    将创建一个临时队列,并将其用于来自此网关实例的所有回复。 消息中不需要关联数据,但传出数据在网关内部用于将回复定向到正确的请求线程。JMSMessageIDSpring中文文档

  7. 提供属性,提供属性,不提供属性reply-destination*<reply-listener>correlation-keySpring中文文档

    不允许。Spring中文文档

    该配置将被忽略,网关的行为与 中 相同。 将写入警告日志消息以指示这种情况。<reply-listener/>2Spring中文文档

  8. 提供属性,提供属性,以及reply-destination*<reply-listener>correlation-key="JMSCorrelationID"Spring中文文档

    网关具有唯一的相关 ID,并将其与标头 () 中的递增值一起插入。 消息选择器为:JMSCorrelationIDgatewayId + "_" + ++seqSpring中文文档

    messageSelector = "JMSCorrelationID LIKE '" + gatewayId%'"Spring中文文档

    应答系统应在应答中返回入站。 这是一种常见的模式,由 Spring Integration 入站网关以及用于消息驱动的 POJO 的 Spring 实现。 由于每个网关都有一个唯一的 ID,因此每个实例只获得自己的回复。 完整的关联数据用于将回复路由到正确的请求线程。JMSCorrelationIDJMSCorrelationIDMessageListenerAdapterSpring中文文档

  9. 提供属性,并提供属性,并且reply-destination*<reply-listener/>correlation-key="myCorrelationHeader"Spring中文文档

    网关具有唯一的相关 ID,并将其与属性 () 中的递增值一起插入。 可以是任何用户定义的值。 消息选择器为:myCorrelationHeadergatewayId + "_" + ++seqcorrelation-keySpring中文文档

    messageSelector = "myCorrelationHeader LIKE '" + gatewayId%'"Spring中文文档

    应答系统应在应答中返回入站。 由于每个网关都有一个唯一的 ID,因此每个实例只获得自己的回复。 完整的关联数据用于将回复路由到正确的请求线程。myCorrelationHeadermyCorrelationHeaderSpring中文文档

  10. 提供属性,提供属性,以及reply-destination*<reply-listener/>correlation-key="JMSCorrelationID*"Spring中文文档

    (请注意相关键中的 )*Spring中文文档

    不允许。Spring中文文档

    用户提供的相关 ID 不允许与应答侦听器一起使用。 网关不会使用此配置进行初始化。Spring中文文档

异步网关

从 V4.3 开始,您现在可以在配置出站网关时指定(或在 Java 中指定)。async="true"setAsync(true)Spring中文文档

默认情况下,当请求发送到网关时,请求线程将暂停,直到收到回复。 然后,该流在该线程上继续。 如果为 ,则在完成后立即释放请求线程,并在侦听器容器线程上返回回复(并且流继续)。 在轮询器线程上调用网关时,这可能很有用。 线程已发布,可用于框架中的其他任务。asynctruesend()Spring中文文档

您需要一个(或在使用 Java 配置时)。 它还需要指定一个(通常)。 如果不满足其中任一条件,则忽略。async<reply-listener/>setUseReplyContainer(true)correlationKeyJMSCorrelationIDasyncSpring中文文档

属性参考

以下列表显示了 : 的所有可用属性:outbound-gatewaySpring中文文档

<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.ConnectionFactoryjmsConnectionFactory
2 包含用于将响应与回复关联的关联数据的属性的名称。 如果省略,网关希望响应系统返回标头中出站标头的值。 如果指定,网关将生成相关 ID,并用该 ID 填充指定的属性。 响应系统必须在同一属性中回显该值。 可以将其设置为 ,在这种情况下,使用标准标头而不是属性来保存相关数据。 使用 时,必须指定 if you provide an explicit . 从版本 4.0.1 开始,此属性还支持值 ,这意味着如果出站消息已经具有(从 )标头映射,则使用该标头而不是生成新标头。 请注意,使用 时不允许使用密钥,因为容器需要在初始化期间设置消息选择器。JMSMessageIDJMSCorrelationIDJMSCorrelationIDString<reply-container/>correlation-keyreply-destinationJMSCorrelationID*JMSCorrelationIDjms_correlationIdJMSCorrelationID*<reply-container/>
您应该了解,网关无法确保唯一性,如果提供的相关 ID 不唯一,则可能会发生意外的副作用。
3 一个布尔值,指示传递模式应为 () 还是 ()。 仅当 为 时,此设置才会生效。DeliveryMode.PERSISTENTtrueDeliveryMode.NON_PERSISTENTfalseexplicit-qos-enabledtrue
4 一个。 默认值为 ,它将目标名称映射到该名称的队列或主题。DestinationResolverDynamicDestinationResolver
5 设置为 时,它允许使用服务质量属性:、 和 。trueprioritydelivery-modetime-to-live
6 当设置为(缺省值)时,Spring Integration 回复消息的有效负载将从 JMS 回复消息的正文创建(通过使用 )。 当设置为 时,整个 JMS 消息将成为 Spring Integration 消息的有效负载。trueMessageConverterfalse
7 当设置为(默认值)时,Spring Integration 消息的有效负载将转换为 (通过使用 )。 当设置为 时,整个 Spring 集成消息将转换为 。 在这两种情况下,Spring Integration 消息头都使用 .trueJMSMessageMessageConverterfalseJMSMessageHeaderMapper
8 用于将 Spring Integration 消息头映射到 JMS 消息头和属性以及从 JMS 消息头和属性映射。HeaderMapper
9 对 a 的引用,用于在 JMS 消息和 Spring Integration 消息有效负载(如果为 )之间进行转换。 默认值为 .MessageConverterextract-request-payloadfalseSimpleMessageConverter
10 请求消息的默认优先级。 被邮件优先级标头覆盖(如果存在)。 它的范围是 。 仅当 为 时,此设置才会生效。09explicit-qos-enabledtrue
11 等待回复的时间(以毫秒为单位)。 默认值为(5 秒)。5000
12 将回复消息发送到的频道。
13 对 的引用,该引用设置为标头。 最多只允许使用 、 或 之一。 如果未提供任何信息,则使用 a 对此网关进行回复。DestinationJMSReplyToreply-destinationreply-destination-expressionreply-destination-nameTemporaryQueue
14 计算结果为 的 SpEL 表达式,该表达式将设置为标头。 表达式可以生成对象或 . 它用于解析实际的 . 最多只允许使用 、 或 之一。 如果未提供任何信息,则使用 a 对此网关进行回复。DestinationJMSReplyToDestinationStringDestinationResolverDestinationreply-destinationreply-destination-expressionreply-destination-nameTemporaryQueue
15 设置为 JMSReplyTo 标头的目标的名称。 它用于解析实际的 . 最多只允许使用 、 或 之一。 如果未提供任何信息,则使用 a 对此网关进行回复。DestinationResolverDestinationreply-destinationreply-destination-expressionreply-destination-nameTemporaryQueue
16 当设置为 时,它表示由 解析的任何回复都应该是 而不是 。trueDestinationDestinationResolverTopicQueue
17 网关在向 . 仅当 can 阻塞时,这才会生效,例如当前容量限制已满。 默认值为无穷大。reply-channelreply-channelQueueChannel
18 此网关接收请求消息的通道。
19 对向其发送请求消息的引用。 、 或 之一为必填项。 您只能使用这三个属性之一。Destinationreply-destinationreply-destination-expressionreply-destination-name
20 一个 SpEL 表达式,计算结果为向其发送请求消息。 表达式可以生成对象或 . 它用于解析实际的 . 、 或 之一为必填项。 您只能使用这三个属性之一。DestinationDestinationStringDestinationResolverDestinationreply-destinationreply-destination-expressionreply-destination-name
21 请求消息发送到的目标的名称。 它用于解析实际的 . 、 或 之一为必填项。 您只能使用这三个属性之一。DestinationResolverDestinationreply-destinationreply-destination-expressionreply-destination-name
22 当设置为 时,它表示由 解析的任何请求都应该是 而不是 。trueDestinationDestinationResolverTopicQueue
23 指定要生存的消息时间。 仅当 为 时,此设置才会生效。explicit-qos-enabledtrue
24 指定此出站网关是否必须返回非 null 值。 默认情况下,此值为 ,当基础服务在 之后未返回值时,将抛出 a。 请注意,如果服务从不期望返回回复,则最好使用 a 而不是 with 。 对于后者,发送线程被阻塞,等待该时间段的回复。trueMessageTimeoutExceptionreceive-timeout<int-jms:outbound-channel-adapter/><int-jms:outbound-gateway/>requires-reply="false"receive-timeout
25 当您使用 时,默认情况下,其生命周期(启动和停止)与网关的生命周期匹配。 当此值大于 时,容器将按需启动(发送请求时)。 容器将继续运行,直到至少这段时间过去,没有收到任何请求(并且直到没有未完成的回复)。 容器将在下一个请求时再次启动。 停止时间是最小的,实际上可能高达此值的 1.5 倍。<reply-listener />0
26 请参阅异步网关
27 包含此元素时,异步接收回复,而不是为每个回复创建使用者。 在许多情况下,这可能更有效。MessageListenerContainer

将 (或 ) 与 cacheConsumers 设置为的 一起使用可能会导致内存不足情况。 这是因为每个请求都会使用新的选择器获取新的使用者(在发送的 JMSMessageID 上选择值或当没有时选择)。 鉴于这些选择器是唯一的,因此在当前请求完成后,它们将保留在缓存中(未使用)。reply-destinationreply-destination-nameCachingConnectionFactorytruecorrelation-keycorrelation-keySpring中文文档

如果指定了应答目标,建议不要使用缓存的使用者。 或者,考虑使用如下所述<reply-listener/>Spring中文文档

如果指定应答侦听器并指定应答目标(或应答目标名称),但未提供相关键,则网关将记录警告并回退到 V2.2 之前的行为。 这是因为在这种情况下无法配置选择器。 因此,无法避免应答转到可能配置了相同应答目标的不同网关。Spring中文文档

请注意,在这种情况下,每个请求都会使用一个新的使用者,并且使用者可以按照上述警告中的描述在内存中建立;因此,在这种情况下不应使用缓存的使用者。Spring中文文档

使用此配置时,不应使用主题进行回复。 答复可能会丢失。
1 对 . 默认 .jakarta.jms.ConnectionFactoryjmsConnectionFactory
2 包含用于将响应与回复关联的关联数据的属性的名称。 如果省略,网关希望响应系统返回标头中出站标头的值。 如果指定,网关将生成相关 ID,并用该 ID 填充指定的属性。 响应系统必须在同一属性中回显该值。 可以将其设置为 ,在这种情况下,使用标准标头而不是属性来保存相关数据。 使用 时,必须指定 if you provide an explicit . 从版本 4.0.1 开始,此属性还支持值 ,这意味着如果出站消息已经具有(从 )标头映射,则使用该标头而不是生成新标头。 请注意,使用 时不允许使用密钥,因为容器需要在初始化期间设置消息选择器。JMSMessageIDJMSCorrelationIDJMSCorrelationIDString<reply-container/>correlation-keyreply-destinationJMSCorrelationID*JMSCorrelationIDjms_correlationIdJMSCorrelationID*<reply-container/>
您应该了解,网关无法确保唯一性,如果提供的相关 ID 不唯一,则可能会发生意外的副作用。
3 一个布尔值,指示传递模式应为 () 还是 ()。 仅当 为 时,此设置才会生效。DeliveryMode.PERSISTENTtrueDeliveryMode.NON_PERSISTENTfalseexplicit-qos-enabledtrue
4 一个。 默认值为 ,它将目标名称映射到该名称的队列或主题。DestinationResolverDynamicDestinationResolver
5 设置为 时,它允许使用服务质量属性:、 和 。trueprioritydelivery-modetime-to-live
6 当设置为(缺省值)时,Spring Integration 回复消息的有效负载将从 JMS 回复消息的正文创建(通过使用 )。 当设置为 时,整个 JMS 消息将成为 Spring Integration 消息的有效负载。trueMessageConverterfalse
7 当设置为(默认值)时,Spring Integration 消息的有效负载将转换为 (通过使用 )。 当设置为 时,整个 Spring 集成消息将转换为 。 在这两种情况下,Spring Integration 消息头都使用 .trueJMSMessageMessageConverterfalseJMSMessageHeaderMapper
8 用于将 Spring Integration 消息头映射到 JMS 消息头和属性以及从 JMS 消息头和属性映射。HeaderMapper
9 对 a 的引用,用于在 JMS 消息和 Spring Integration 消息有效负载(如果为 )之间进行转换。 默认值为 .MessageConverterextract-request-payloadfalseSimpleMessageConverter
10 请求消息的默认优先级。 被邮件优先级标头覆盖(如果存在)。 它的范围是 。 仅当 为 时,此设置才会生效。09explicit-qos-enabledtrue
11 等待回复的时间(以毫秒为单位)。 默认值为(5 秒)。5000
12 将回复消息发送到的频道。
13 对 的引用,该引用设置为标头。 最多只允许使用 、 或 之一。 如果未提供任何信息,则使用 a 对此网关进行回复。DestinationJMSReplyToreply-destinationreply-destination-expressionreply-destination-nameTemporaryQueue
14 计算结果为 的 SpEL 表达式,该表达式将设置为标头。 表达式可以生成对象或 . 它用于解析实际的 . 最多只允许使用 、 或 之一。 如果未提供任何信息,则使用 a 对此网关进行回复。DestinationJMSReplyToDestinationStringDestinationResolverDestinationreply-destinationreply-destination-expressionreply-destination-nameTemporaryQueue
15 设置为 JMSReplyTo 标头的目标的名称。 它用于解析实际的 . 最多只允许使用 、 或 之一。 如果未提供任何信息,则使用 a 对此网关进行回复。DestinationResolverDestinationreply-destinationreply-destination-expressionreply-destination-nameTemporaryQueue
16 当设置为 时,它表示由 解析的任何回复都应该是 而不是 。trueDestinationDestinationResolverTopicQueue
17 网关在向 . 仅当 can 阻塞时,这才会生效,例如当前容量限制已满。 默认值为无穷大。reply-channelreply-channelQueueChannel
18 此网关接收请求消息的通道。
19 对向其发送请求消息的引用。 、 或 之一为必填项。 您只能使用这三个属性之一。Destinationreply-destinationreply-destination-expressionreply-destination-name
20 一个 SpEL 表达式,计算结果为向其发送请求消息。 表达式可以生成对象或 . 它用于解析实际的 . 、 或 之一为必填项。 您只能使用这三个属性之一。DestinationDestinationStringDestinationResolverDestinationreply-destinationreply-destination-expressionreply-destination-name
21 请求消息发送到的目标的名称。 它用于解析实际的 . 、 或 之一为必填项。 您只能使用这三个属性之一。DestinationResolverDestinationreply-destinationreply-destination-expressionreply-destination-name
22 当设置为 时,它表示由 解析的任何请求都应该是 而不是 。trueDestinationDestinationResolverTopicQueue
23 指定要生存的消息时间。 仅当 为 时,此设置才会生效。explicit-qos-enabledtrue
24 指定此出站网关是否必须返回非 null 值。 默认情况下,此值为 ,当基础服务在 之后未返回值时,将抛出 a。 请注意,如果服务从不期望返回回复,则最好使用 a 而不是 with 。 对于后者,发送线程被阻塞,等待该时间段的回复。trueMessageTimeoutExceptionreceive-timeout<int-jms:outbound-channel-adapter/><int-jms:outbound-gateway/>requires-reply="false"receive-timeout
25 当您使用 时,默认情况下,其生命周期(启动和停止)与网关的生命周期匹配。 当此值大于 时,容器将按需启动(发送请求时)。 容器将继续运行,直到至少这段时间过去,没有收到任何请求(并且直到没有未完成的回复)。 容器将在下一个请求时再次启动。 停止时间是最小的,实际上可能高达此值的 1.5 倍。<reply-listener />0
26 请参阅异步网关
27 包含此元素时,异步接收回复,而不是为每个回复创建使用者。 在许多情况下,这可能更有效。MessageListenerContainer
您应该了解,网关无法确保唯一性,如果提供的相关 ID 不唯一,则可能会发生意外的副作用。

将消息头映射到 JMS 消息和从 JMS 消息映射消息

JMS 消息可以包含元信息,例如 JMS API 头和简单属性。 您可以使用 将这些内容映射到 Spring Integration 消息头或从 Spring Integration 消息头映射。 JMS API 标头被传递给相应的 setter 方法(比如 ),而其他标头则被复制到 JMS 消息的常规属性中。 JMS 出站网关是使用 的缺省实现引导的,它将映射标准 JMS API 标头以及原语或消息标头。 您还可以使用入站和出站网关的属性提供自定义标头映射器。JmsHeaderMappersetJMSReplyToJmsHeaderMapperStringheader-mapperSpring中文文档

许多特定于 JMS 供应商的客户机不允许直接在已创建的 JMS 消息上设置 和 属性。 它们被视为 QoS 属性,因此必须传播到目标 API。 因此,不会将适当的Spring Integration标头(或表达式结果)映射到提到的JMS消息属性中。 相反,a 用于将标头值从请求消息传播到 API。 若要启用此功能,必须使用 a 配置出站终结点,并将其属性设置为 true。 Spring Integration Java DSL 默认配置 a,但仍必须设置该属性。deliveryModeprioritytimeToLiveMessageProducer.send(message, deliveryMode, priority, timeToLive)DefaultJmsHeaderMapperDynamicJmsTemplateJmsSendingMessageHandlerMessageProducer.send()DynamicJmsTemplateexplicitQosEnabledDynamicJmsTemplateexplicitQosEnabled
从版本 4.0 开始,标头映射到入站邮件的标准标头。 以前,标头仅用于出站消息。 若要恢复到上一个行为(即不映射入站优先级),请将 的属性设置为 。JMSPrioritypriorityprioritymapInboundPriorityDefaultJmsHeaderMapperfalse
从 V4.3 开始,通过调用其方法将标准标头映射为消息属性( 通常是 ,JMS 不支持)。 在入站端,它被映射为 . 这与标头无关,标头映射到标头和从标头映射。 通常用于关联请求和回复,而 通常用于将相关消息组合到一个组中(例如使用聚合器或重排序器)。DefaultJmsHeaderMappercorrelationIdtoString()correlationIdUUIDStringjms_correlationIdJMSCorrelationIDJMSCorrelationIDcorrelationId

从版本 5.1 开始,可以配置映射入站和属性:DefaultJmsHeaderMapperJMSDeliveryModeJMSExpirationSpring中文文档

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

这些 JMS 属性分别映射到 和 Spring Message 标头。JmsHeaders.DELIVERY_MODEJmsHeaders.EXPIRATIONSpring中文文档

许多特定于 JMS 供应商的客户机不允许直接在已创建的 JMS 消息上设置 和 属性。 它们被视为 QoS 属性,因此必须传播到目标 API。 因此,不会将适当的Spring Integration标头(或表达式结果)映射到提到的JMS消息属性中。 相反,a 用于将标头值从请求消息传播到 API。 若要启用此功能,必须使用 a 配置出站终结点,并将其属性设置为 true。 Spring Integration Java DSL 默认配置 a,但仍必须设置该属性。deliveryModeprioritytimeToLiveMessageProducer.send(message, deliveryMode, priority, timeToLive)DefaultJmsHeaderMapperDynamicJmsTemplateJmsSendingMessageHandlerMessageProducer.send()DynamicJmsTemplateexplicitQosEnabledDynamicJmsTemplateexplicitQosEnabled
从版本 4.0 开始,标头映射到入站邮件的标准标头。 以前,标头仅用于出站消息。 若要恢复到上一个行为(即不映射入站优先级),请将 的属性设置为 。JMSPrioritypriorityprioritymapInboundPriorityDefaultJmsHeaderMapperfalse
从 V4.3 开始,通过调用其方法将标准标头映射为消息属性( 通常是 ,JMS 不支持)。 在入站端,它被映射为 . 这与标头无关,标头映射到标头和从标头映射。 通常用于关联请求和回复,而 通常用于将相关消息组合到一个组中(例如使用聚合器或重排序器)。DefaultJmsHeaderMappercorrelationIdtoString()correlationIdUUIDStringjms_correlationIdJMSCorrelationIDJMSCorrelationIDcorrelationId

邮件转换、封送和取消封组

如果需要转换消息,那么所有 JMS 适配器和网关都允许您通过设置属性来提供消息。 为此,请提供同一 ApplicationContext 中可用的实例的 Bean 名称。 此外,为了提供与编组器和解编器接口的一致性,Spring 提供了 ,您可以使用自己的自定义编组器和取消编组器进行配置。 下面的示例演示如何执行此操作MessageConvertermessage-converterMessageConverterMarshallingMessageConverterSpring中文文档

<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>
当您提供自己的实例时,它仍包装在 . 这意味着“提取-请求-有效负载”和“提取-回复-有效负载”属性可能会影响传递给转换器的实际对象。 它本身委托给一个目标,同时还将Spring Integration映射到JMS消息属性,然后再映射回来。MessageConverterHeaderMappingMessageConverterHeaderMappingMessageConverterMessageConverterMessageHeaders
当您提供自己的实例时,它仍包装在 . 这意味着“提取-请求-有效负载”和“提取-回复-有效负载”属性可能会影响传递给转换器的实际对象。 它本身委托给一个目标,同时还将Spring Integration映射到JMS消息属性,然后再映射回来。MessageConverterHeaderMappingMessageConverterHeaderMappingMessageConverterMessageConverterMessageHeaders

JMS 支持的消息通道

前面介绍的通道适配器和网关都适用于与其他外部系统集成的应用程序。 入站选项假定其他系统正在向 JMS 目标发送 JMS 消息,而出站选项假定其他系统正在从目标接收消息。 另一个系统可能是也可能不是 Spring Integration 应用程序。 当然,当将 Spring Integration 消息实例作为 JMS 消息本身的正文发送时(“extract-payload”值设置为 ),假定另一个系统基于 Spring Integration。 但是,这绝不是必需的。 这种灵活性是使用基于消息的集成选项的好处之一,该选项抽象了“通道”(在 JMS 的情况下是目标)。falseSpring中文文档

有时,给定 JMS 目标的生产者和使用者都打算成为同一应用程序的一部分,在同一进程中运行。 您可以使用一对入站和出站通道适配器来实现此目的。 这种方法的问题在于,您需要两个适配器,尽管从概念上讲,目标是具有单个消息通道。 从 Spring Integration 版本 2.0 开始支持更好的选项。 现在,在使用 JMS 名称空间时,可以定义单个“通道”,如以下示例所示:Spring中文文档

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

前面示例中的通道的行为与主 Spring Integration 命名空间中的普通元素非常相似。 它可以由任何终结点的 和 属性引用。 不同之处在于,此通道由名为 的 JMS 队列实例提供支持。 这意味着在生产端点和使用端点之间可以进行异步消息传递。 但是,与通过在非 JMS 元素中添加元素而创建的更简单的异步消息通道不同,消息不会存储在内存队列中。 相反,这些消息在 JMS 消息正文中传递,然后底层 JMS 提供程序的全部功能可用于该通道。 使用此替代方法的最常见理由可能是利用 JMS 消息传递的存储和转发方法提供的持久性。<channel/>input-channeloutput-channelexampleQueue<queue/><channel/>Spring中文文档

如果配置正确,JMS 支持的消息通道也支持事务。 换言之,如果生产者发送操作是回滚事务的一部分,则生产者实际上不会写入事务性 JMS 支持的通道。 同样,如果接收 JMS 消息是回滚事务的一部分,那么使用者不会从通道中物理删除该消息。 请注意,在这种情况下,生产者和使用者事务是分开的。 这与在没有子元素的简单同步元素上传播事务上下文有很大不同。<channel/><queue/>Spring中文文档

由于上面的示例引用了 JMS 队列实例,因此它充当点对点通道。 另一方面,如果需要发布-订阅行为,则可以使用单独的元素并引用 JMS 主题。 以下示例演示如何执行此操作:Spring中文文档

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

对于任一类型的 JMS 支持的通道,都可以提供目标的名称而不是引用,如以下示例所示:Spring中文文档

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

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

在前面的示例中,目标名称由 Spring 的默认实现解析,但您可以提供接口的任何实现。 此外,JMS 是通道的必需属性,但默认情况下,预期的 Bean 名称为 。 以下示例既提供了用于解析 JMS 目标名称的自定义实例,也提供了用于解析 JMS 目标名称的不同名称:DynamicDestinationResolverDestinationResolverConnectionFactoryjmsConnectionFactoryConnectionFactorySpring中文文档

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

对于 ,将属性设置为 for a durable subscription or for a shared subscription(需要 JMS 2.0 代理,并且从 V4.2 开始可用)。 用于命名订阅。<publish-subscribe-channel />durabletruesubscription-sharedsubscriptionSpring中文文档

使用 JMS 消息选择器

使用 JMS 消息选择器,您可以根据 JMS 头和 JMS 属性来过滤 JMS 消息。 例如,如果要侦听其定制 JMS 标头属性 , 等于 的消息,可以指定以下表达式:myHeaderPropertysomethingSpring中文文档

myHeaderProperty = 'something'

消息选择器表达式是 SQL-92 条件表达式语法的子集,被定义为 Java 消息服务规范的一部分。 您可以使用以下 Spring Integration JMS 组件的 XML 命名空间配置来指定 JMS 消息属性:selectorSpring中文文档

不能使用 JMS 消息选择器来引用消息正文值。
不能使用 JMS 消息选择器来引用消息正文值。

JMS 示例

要试验这些 JMS 适配器,请查看 Spring Integration Samples Git 存储库中提供的 JMS 示例,网址为 https://github.com/spring-projects/spring-integration-samples/tree/master/basic/jmsSpring中文文档

该存储库包含两个示例。 一个提供入站和出站通道适配器,另一个提供入站和出站网关。 它们配置为使用嵌入式 ActiveMQ 进程运行,但您可以修改每个示例的 common.xml Spring 应用程序上下文文件,以支持不同的 JMS 提供程序或独立的 ActiveMQ 进程。Spring中文文档

换言之,您可以拆分配置,以便入站和出站适配器在单独的 JVM 中运行。 如果已安装 ActiveMQ,请修改文件中的属性以使用(而不是 )。 两个样本都接受来自 stdin 的输入并回显回 stdout。 查看配置,了解这些消息是如何通过 JMS 路由的。brokerURLcommon.xmltcp://localhost:61616vm://localhostSpring中文文档