跳到主要内容
版本:3.4.3

JMS

DeepSeek V3 中英对照 JMS

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

ActiveMQ "经典" 版支持

ActiveMQ "Classic" 在类路径上可用时,Spring Boot 可以配置一个 ConnectionFactory。如果代理存在,则会自动启动并配置一个嵌入式代理(前提是没有通过配置指定代理 URL 并且嵌入式代理在配置中未被禁用)。

备注

如果你使用 spring-boot-starter-activemq,那么连接 ActiveMQ "Classic" 实例所需的依赖项将会被提供,同时也会提供与 JMS 集成的 Spring 基础设施。在你的应用程序中添加 org.apache.activemq:activemq-broker 可以让你使用嵌入式的 broker。

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

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

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

spring.activemq.embedded.enabled=false

如果配置了代理 URL,嵌入式代理也将被禁用,如下例所示:

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

如果你想完全控制嵌入的代理,请参阅 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 时自动配置一个 ConnectionFactory。如果代理存在,Spring Boot 将自动启动并配置一个嵌入式代理(除非明确设置了模式属性)。支持的模式包括 embedded(明确表示需要一个嵌入式代理,如果类路径中不可用则报错)和 native(使用 netty 传输协议连接到代理)。当配置为后者时,Spring Boot 会配置一个 ConnectionFactory,该工厂使用默认设置连接到本地机器上运行的代理。

备注

如果你使用 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 的 JmsTemplate 是自动配置的,你可以直接将其自动注入到你自己的 bean 中,如下例所示:

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

@Component
public class MyBean {

private final JmsTemplate jmsTemplate;

public MyBean(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}

// ...

public void someMethod() {
this.jmsTemplate.convertAndSend("hello");
}

}
备注

JmsMessagingTemplate 可以以类似的方式注入。如果定义了 DestinationResolverMessageConverter bean,它会自动与自动配置的 JmsTemplate 关联。

接收消息

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

在大多数情况下,消息监听器容器应配置为使用原生的 ConnectionFactory。这样每个监听器容器都有自己的连接,从而在本地恢复方面拥有完全的责任。自动配置会使用 ConnectionFactoryUnwrapper 从自动配置的连接工厂中解包出原生连接工厂。

备注

自动配置仅解包 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.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.boot.jms.ConnectionFactoryUnwrapper;
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) {
// ...
}

}