跳到主要内容
版本:4.0.2

JMS

QWen Max 中英对照 JMS

ConnectionFactory 接口提供了一种标准方法,用于创建与 JMS 代理进行交互的 Connection。尽管 Spring 需要一个 ConnectionFactory 来使用 JMS,但你通常无需直接使用它,而是可以依赖更高层次的消息抽象。(详情请参阅 Spring Framework 参考文档的相关章节。)Spring Boot 还会自动配置发送和接收消息所需的基础设施。

ActiveMQ "Classic" 支持

ActiveMQ "Classic" 位于 classpath 中时,Spring Boot 可以配置一个 ConnectionFactory。如果存在 broker,则会自动启动并配置一个嵌入式 broker(前提是未通过配置指定 broker URL,并且在配置中未禁用嵌入式 broker)。

备注

如果你使用 spring-boot-starter-activemq,则会自动提供连接到 ActiveMQ "Classic" 实例所需的依赖项,以及与 JMS 集成的 Spring 基础设施。在你的应用中添加 org.apache.activemq:activemq-broker 可以让你使用嵌入式 broker。

ActiveMQ "Classic" 的配置由 spring.activemq.* 中的外部配置属性控制。

如果 activemq-broker 在类路径中,ActiveMQ "Classic" 会自动配置为使用 VM transport,该传输方式会在同一个 JVM 实例中启动一个嵌入式 broker。

你可以通过配置 spring.activemq.embedded.enabled 属性来禁用嵌入式 broker,如下例所示:

spring.activemq.embedded.enabled=false

如果你配置了 broker URL,嵌入式 broker 也会被禁用,如下例所示:

spring.activemq.broker-url=tcp://192.168.1.210:9876
spring.activemq.user=admin
spring.activemq.password=secret

如果你想完全控制嵌入式 broker,请参阅 ActiveMQ "Classic" 文档 以获取更多信息。

默认情况下,CachingConnectionFactory 会以合理的设置包装原生的 ConnectionFactory,这些设置可以通过 spring.jms.* 中的外部配置属性进行控制:

spring.jms.cache.session-cache-size=5

如果你更倾向于使用原生连接池,可以通过添加 org.messaginghub:pooled-jms 依赖,并相应地配置 JmsPoolConnectionFactory,如下例所示:

spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=50
提示

有关更多支持的选项,请参见 ActiveMQProperties。你还可以注册任意数量实现 ActiveMQConnectionFactoryCustomizer 的 Bean,以进行更高级的自定义。

默认情况下,ActiveMQ "Classic" 会在目的地尚不存在时创建该目的地,以便根据所提供的名称解析目的地。

ActiveMQ Artemis 支持

当 Spring Boot 检测到 ActiveMQ Artemis 在 classpath 上可用时,它可以自动配置一个 ConnectionFactory。如果存在该 broker,则会自动启动并配置一个嵌入式 broker(除非显式设置了 mode 属性)。支持的模式有 embedded(明确要求使用嵌入式 broker,如果 classpath 上没有该 broker 则抛出错误)和 native(使用 netty 传输协议连接到 broker)。当配置为后者时,Spring Boot 会配置一个 ConnectionFactory,以默认设置连接到本地机器上运行的 broker。

备注

如果你使用 spring-boot-starter-artemis,则会自动提供连接到现有 ActiveMQ Artemis 实例所需的依赖项,以及与 JMS 集成的 Spring 基础设施。在你的应用中添加 org.apache.activemq:artemis-jakarta-server 可以让你使用嵌入式模式。

ActiveMQ Artemis 的配置由 spring.artemis.* 中的外部配置属性控制。例如,你可以在 application.properties 中声明以下内容:

spring.artemis.mode=native
spring.artemis.broker-url=tcp://192.168.1.210:9876
spring.artemis.user=admin
spring.artemis.password=secret

在嵌入 broker 时,你可以选择是否启用持久化,并列出应提供的目的地。这些目的地可以指定为一个逗号分隔的列表,以使用默认选项创建;或者,你也可以分别定义类型为 JMSQueueConfigurationTopicConfiguration 的 bean,用于高级队列和主题配置。

默认情况下,CachingConnectionFactory 会以合理的设置包装原生的 ConnectionFactory,你可以通过 spring.jms.* 中的外部配置属性来控制这些设置:

spring.jms.cache.session-cache-size=5

如果你更倾向于使用原生连接池,可以通过添加对 org.messaginghub:pooled-jms 的依赖,并相应地配置 JmsPoolConnectionFactory,如下例所示:

spring.artemis.pool.enabled=true
spring.artemis.pool.max-connections=50

更多支持的选项请参见 ArtemisProperties

不涉及 JNDI 查找,目的地通过其名称进行解析,使用的是 ActiveMQ Artemis 配置中的 name 属性或通过配置提供的名称。

使用 JNDI ConnectionFactory

如果你在应用服务器中运行你的应用程序,Spring Boot 会尝试通过 JNDI 查找一个 JMS ConnectionFactory。默认情况下,会检查 java:/JmsXAjava:/XAConnectionFactory 这两个位置。如果你需要指定一个替代的位置,可以使用 spring.jms.jndi-name 属性,如下例所示:

spring.jms.jndi-name=java:/MyConnectionFactory

发送消息

Spring 的 JmsClient 会自动配置,你可以直接将其注入到你自己的 bean 中,如下例所示:

import org.springframework.jms.core.JmsClient;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

private final JmsClient jmsClient;

public MyBean(JmsClient jmsClient) {
this.jmsClient = jmsClient;
}

// ...

public void someMethod() {
this.jmsClient.destination("myQueue").send("hello");
}

}
备注

JmsMessagingTemplate 可以以类似的方式注入,二者都使用传统的 JmsTemplate,该模板也可以被注入。如果定义了 DestinationResolverMessageConverter bean,它们会自动关联到自动配置的 JmsTemplate

接收消息

当 JMS 基础设施存在时,任何 Bean 都可以使用 @JmsListener 注解来创建一个监听器端点。如果没有定义 JmsListenerContainerFactory,则会自动配置一个默认的工厂。如果定义了 DestinationResolverMessageConverterExceptionListener Bean,它们会自动与默认工厂关联。

在大多数场景中,消息监听器容器应针对原生的 ConnectionFactory 进行配置。这样,每个监听器容器都拥有自己的连接,从而在本地恢复方面具备完全的控制权。自动配置使用 ConnectionFactoryUnwrapper 从自动配置的 ConnectionFactory 中解包出原生的连接工厂。

备注

自动配置仅解包 CachedConnectionFactory

默认情况下,该默认工厂是事务性的。如果你运行在一个存在 JtaTransactionManager 的基础设施中,它会默认与监听器容器关联。如果不存在,则启用 sessionTransacted 标志。在后一种场景下,你可以通过在监听器方法(或其委托方法)上添加 @Transactional 注解,将本地数据存储的事务与传入消息的处理关联起来。这确保了在本地事务完成后,传入的消息才会被确认。这也包括在同一 JMS 会话中执行的响应消息的发送。

以下组件在 someQueue 目的地创建了一个监听器端点:

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

@JmsListener(destination = "someQueue")
public void processMessage(String content) {
// ...
}

}
提示

更多详情请参见 @EnableJms 的 API 文档。

如果你需要创建更多的 JmsListenerContainerFactory 实例,或者想要覆盖默认配置,Spring Boot 提供了一个 DefaultJmsListenerContainerFactoryConfigurer,你可以使用它来初始化一个 DefaultJmsListenerContainerFactory,并应用与自动配置的实例相同的设置。

例如,以下示例暴露了另一个使用特定 MessageConverter 的工厂:

import jakarta.jms.ConnectionFactory;

import org.springframework.boot.jms.ConnectionFactoryUnwrapper;
import org.springframework.boot.jms.autoconfigure.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;

@Configuration(proxyBeanMethods = false)
public class MyJmsConfiguration {

@Bean
public DefaultJmsListenerContainerFactory myFactory(DefaultJmsListenerContainerFactoryConfigurer configurer,
ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
configurer.configure(factory, ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory));
factory.setMessageConverter(new MyMessageConverter());
return factory;
}

}
备注

在上面的示例中,自定义配置使用了 ConnectionFactoryUnwrapper,以与自动配置的工厂相同的方式将原生连接工厂关联到消息监听器容器。

然后你可以在任意使用 @JmsListener 注解的方法中按如下方式使用该工厂:

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

@JmsListener(destination = "someQueue", containerFactory = "myFactory")
public void processMessage(String content) {
// ...
}

}