此版本仍在开发中,尚未视为稳定版。如需最新稳定版本,请使用 Spring Boot 4.0.4spring-doc.cadn.net.cn

JMS

ConnectionFactory 接口提供了一种创建 Connection 的标准方法,用于与 JMS 代理进行交互。 虽然 Spring 需要 ConnectionFactory 才能与 JMS 协同工作,但您通常无需直接使用它,而是可以依赖更高级的消息抽象。 (有关详细信息,请参阅 Spring Framework 参考文档的相关部分。) Spring Boot 还会自动配置发送和接收消息所需的基础设施。spring-doc.cadn.net.cn

ActiveMQ "Classic" 支持

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

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

ActiveMQ "Classic" 的配置由 spring.activemq.* 中的外部配置属性控制。spring-doc.cadn.net.cn

如果 activemq-broker 在类路径中,ActiveMQ “Classic” 将自动配置为使用VM 传输,这会在同一个 JVM 实例中启动一个嵌入式代理。spring-doc.cadn.net.cn

您可以通过配置 spring.activemq.embedded.enabled 属性来禁用内嵌的代理,如下例所示:spring-doc.cadn.net.cn

spring.activemq.embedded.enabled=false
spring:
  activemq:
    embedded:
      enabled: false

如果配置了代理URL,嵌入式代理也会被禁用,如下例所示:spring-doc.cadn.net.cn

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

如果您希望完全控制嵌入式代理,请参阅ActiveMQ "Classic" 文档以获取更多信息。spring-doc.cadn.net.cn

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

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

如果您更倾向于使用原生连接池,可以通过添加对 org.messaginghub:pooled-jms 的依赖项并相应配置 JmsPoolConnectionFactory 来实现,如下例所示:spring-doc.cadn.net.cn

spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=50
spring:
  activemq:
    pool:
      enabled: true
      max-connections: 50
请参阅 ActiveMQProperties 以了解更多支持的选项。 您还可以注册任意数量的实现了 ActiveMQConnectionFactoryCustomizer 的 Bean,以实现更高级的自定义。

默认情况下,ActiveMQ "Classic" 会在目标(destination)尚不存在时自动创建该目标,因此目标会根据其提供的名称进行解析。spring-doc.cadn.net.cn

ActiveMQ Artemis 支持

当 Spring Boot 检测到类路径上存在 ActiveMQ Artemis 时,它可以自动配置一个 ConnectionFactory。 如果代理(broker)存在,则会自动启动并配置一个嵌入式代理(除非已显式设置模式属性)。 支持的模式包括 embedded(用于明确指定需要嵌入式代理,并且如果类路径上不可用则应抛出错误)和 native(用于使用 netty 传输协议连接到代理)。 当配置为后者时,Spring Boot 会配置一个 ConnectionFactory,该组件将使用默认设置连接到运行在本地机器上的代理。spring-doc.cadn.net.cn

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

ActiveMQ Artemis 的配置由 spring.artemis.* 中的外部配置属性控制。 例如,你可以在 application.properties 中声明以下配置段:spring-doc.cadn.net.cn

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

在嵌入代理时,您可以选择是否启用持久化,并列出应可用的目标。 这些目标可以指定为逗号分隔的列表以使用默认选项创建它们,或者您可以定义类型为 JMSQueueConfigurationTopicConfiguration 的 Bean,分别用于高级队列和主题配置。spring-doc.cadn.net.cn

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

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

如果您更倾向于使用原生连接池,可以通过添加对 org.messaginghub:pooled-jms 的依赖项并相应配置 JmsPoolConnectionFactory 来实现,如下例所示:spring-doc.cadn.net.cn

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

查看更多支持的选项,请参阅 ArtemisPropertiesspring-doc.cadn.net.cn

不涉及 JNDI 查找,目的地会根据其名称进行解析,使用 ActiveMQ Artemis 配置中的 name 属性或通过配置提供的名称。spring-doc.cadn.net.cn

使用 JNDI ConnectionFactory

如果您在应用服务器中运行应用程序,Spring Boot 会尝试使用 JNDI 定位 JMS ConnectionFactory。 默认情况下,将检查 java:/JmsXAjava:/XAConnectionFactory 位置。 如果需要指定备用位置,可以使用 spring.jms.jndi-name 属性,如下例所示:spring-doc.cadn.net.cn

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

发送消息

Spring 的 JmsTemplate 是自动配置的,您可以直接将其自动装配到您自己的 Bean 中,如下例所示:spring-doc.cadn.net.cn

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");
	}

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

@Component
class MyBean(private val jmsTemplate: JmsTemplate) {

	// ...

	fun someMethod() {
		jmsTemplate.convertAndSend("hello")
	}

}
JmsMessagingTemplate 可以以类似的方式被注入。 如果定义了 DestinationResolverMessageConverter Bean,它将自动关联到自动配置的 JmsTemplate

接收消息

当 JMS 基础设施存在时,任何 Bean 都可以使用 @JmsListener 进行注解,以创建监听器端点。 如果未定义 JmsListenerContainerFactory,系统将自动配置一个默认实例。 如果定义了 DestinationResolverMessageConverterExceptionListener Bean,它们将自动与默认工厂关联。spring-doc.cadn.net.cn

在大多数场景中,消息监听器容器应针对原生 ConnectionFactory 进行配置。 通过这种方式,每个监听器容器都拥有自己的连接,从而使其完全负责本地恢复。 自动配置使用 ConnectionFactoryUnwrapper 从自动配置的工厂中解包原生连接工厂。spring-doc.cadn.net.cn

自动配置仅解包 CachedConnectionFactory

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

以下组件在 someQueue 目标上创建一个监听器端点:spring-doc.cadn.net.cn

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

@Component
public class MyBean {

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

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

@Component
class MyBean {

	@JmsListener(destination = "someQueue")
	fun processMessage(content: String?) {
		// ...
	}

}
请参阅 @EnableJms API 文档以获取更多详情。

如果您需要创建更多 JmsListenerContainerFactory 实例,或者想要覆盖默认配置,Spring Boot 提供了一个 DefaultJmsListenerContainerFactoryConfigurer,您可以使用它来初始化一个 DefaultJmsListenerContainerFactory,其设置与自动配置的实例相同。spring-doc.cadn.net.cn

例如,以下示例公开了另一个使用特定 MessageConverter 的工厂:spring-doc.cadn.net.cn

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;
	}

}
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)
class MyJmsConfiguration {

	@Bean
	fun myFactory(configurer: DefaultJmsListenerContainerFactoryConfigurer,
				  connectionFactory: ConnectionFactory): DefaultJmsListenerContainerFactory {
		val factory = DefaultJmsListenerContainerFactory()
		configurer.configure(factory, ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory))
		factory.setMessageConverter(MyMessageConverter())
		return factory
	}

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

然后,您可以在任何使用 @JmsListener 注解的方法中按如下方式使用该工厂:spring-doc.cadn.net.cn

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) {
		// ...
	}

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

@Component
class MyBean {

	@JmsListener(destination = "someQueue", containerFactory = "myFactory")
	fun processMessage(content: String?) {
		// ...
	}

}