此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10spring-doc.cadn.net.cn

注释驱动的侦听器端点

异步接收消息的最简单方法是使用带注释的侦听器端点基础设施。简而言之,它允许您将托管bean 的方法公开为 JMS 侦听器端点。以下示例显示了如何使用它:spring-doc.cadn.net.cn

@Component
public class MyService {

	@JmsListener(destination = "myDestination")
	public void processOrder(String data) { ... }
}

前面示例的思想是,每当消息在jakarta.jms.Destination myDestinationprocessOrder方法被调用相应地(在本例中,使用 JMS 消息的内容,类似于 什么MessageListenerAdapter提供)。spring-doc.cadn.net.cn

带注释的端点基础设施为每个带注释的方法创建一个消息侦听器容器在后台,通过使用JmsListenerContainerFactory. 此类容器不会针对应用程序上下文进行注册,但可以轻松地通过使用JmsListenerEndpointRegistry豆。spring-doc.cadn.net.cn

@JmsListener是 Java 8 上的可重复注释,因此您可以将多个 JMS 目标与同一方法相关联,方法是添加额外的@JmsListener声明给它。

启用侦听器端点注释

启用对@JmsListener注释,您可以添加@EnableJms到其中一个 你@Configuration类,如以下示例所示:spring-doc.cadn.net.cn

@Configuration
@EnableJms
public class JmsConfiguration {

	@Bean
	public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory,
			DestinationResolver destinationResolver) {

		DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
		factory.setConnectionFactory(connectionFactory);
		factory.setDestinationResolver(destinationResolver);
		factory.setSessionTransacted(true);
		factory.setConcurrency("3-10");
		return factory;
	}
}
@Configuration
@EnableJms
class JmsConfiguration {

	@Bean
	fun jmsListenerContainerFactory(connectionFactory: ConnectionFactory, destinationResolver: DestinationResolver) =
		DefaultJmsListenerContainerFactory().apply {
			setConnectionFactory(connectionFactory)
			setDestinationResolver(destinationResolver)
			setSessionTransacted(true)
			setConcurrency("3-10")
		}
}
<jms:annotation-driven/>

<bean id="jmsListenerContainerFactory" class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
	<property name="connectionFactory" ref="connectionFactory"/>
	<property name="destinationResolver" ref="destinationResolver"/>
	<property name="sessionTransacted" value="true"/>
	<property name="concurrency" value="3-10"/>
</bean>

默认情况下,基础架构会查找名为jmsListenerContainerFactory作为工厂用于创建消息侦听器容器的源。在这种情况下情况(并忽略 JMS 基础设施设置),您可以调用processOrder核心池大小为三个线程,最大池大小为十个线程的方法。spring-doc.cadn.net.cn

您可以自定义要用于每个注解的监听器容器工厂,也可以通过实现JmsListenerConfigurer接口。 仅当至少注册了一个端点而没有特定的容器工厂时,才需要默认值。请参阅实现的类的 javadocJmsListenerConfigurer了解详细信息和示例。spring-doc.cadn.net.cn

编程端点注册

JmsListenerEndpoint提供 JMS 端点的模型,并负责配置该模型的容器。该基础架构允许您以编程方式配置端点除了JmsListener注解。 以下示例显示了如何执行此作:spring-doc.cadn.net.cn

@Configuration
@EnableJms
public class AppConfig implements JmsListenerConfigurer {

	@Override
	public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
		SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();
		endpoint.setId("myJmsEndpoint");
		endpoint.setDestination("anotherQueue");
		endpoint.setMessageListener(message -> {
			// processing
		});
		registrar.registerEndpoint(endpoint);
	}
}

在前面的示例中,我们使用SimpleJmsListenerEndpoint,它提供了实际的MessageListener调用。但是,您也可以构建自己的端点变体来描述自定义调用机制。spring-doc.cadn.net.cn

请注意,您可以跳过使用@JmsListener完全 并通过JmsListenerConfigurer.spring-doc.cadn.net.cn

带注释的端点方法签名

到目前为止,我们一直在注入一个简单的String在我们的端点中,但它实际上可以具有非常灵活的方法签名。在下面的示例中,我们重写它以注入Order跟 自定义标头:spring-doc.cadn.net.cn

@Component
public class MyService {

	@JmsListener(destination = "myDestination")
	public void processOrder(Order order, @Header("order_type") String orderType) {
		...
	}
}

您可以在 JMS 侦听器端点中注入的主要元素如下:spring-doc.cadn.net.cn

  • 原始的jakarta.jms.Message或其任何子类(前提是它与传入消息类型匹配)。spring-doc.cadn.net.cn

  • jakarta.jms.Session用于选择访问本机 JMS API(例如,用于发送自定义回复)。spring-doc.cadn.net.cn

  • org.springframework.messaging.Message表示传入的 JMS 消息。请注意,此消息同时包含自定义标头和标准标头(如定义所示) 由JmsHeaders).spring-doc.cadn.net.cn

  • @Header-带注释的方法参数来提取特定的标头值,包括标准 JMS 标头。spring-doc.cadn.net.cn

  • 一个@Headers-带注释的参数,也必须可以分配给java.util.Map为 访问所有标头。spring-doc.cadn.net.cn

  • 非受支持类型之一的非注释元素 (MessageSession) 被视为有效负载。您可以通过注释参数@Payload. 您还可以通过添加额外的@Valid.spring-doc.cadn.net.cn

注入 Spring 的能力Message抽象对受益特别有用 从存储在传输特定消息中的所有信息中,而不依赖于 传输特定的 API。以下示例显示了如何执行此作:spring-doc.cadn.net.cn

@JmsListener(destination = "myDestination")
public void processOrder(Message<Order> order) { ... }

方法参数的处理由DefaultMessageHandlerMethodFactory,您可以 进一步自定义以支持其他方法参数。您可以自定义转换和验证 那里也有支持。spring-doc.cadn.net.cn

例如,如果我们想确保我们的Order在处理之前有效,我们可以 使用@Valid并配置必要的验证器,如以下示例所示:spring-doc.cadn.net.cn

@Configuration
@EnableJms
public class AppConfig implements JmsListenerConfigurer {

	@Override
	public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
		registrar.setMessageHandlerMethodFactory(myJmsHandlerMethodFactory());
	}

	@Bean
	public DefaultMessageHandlerMethodFactory myHandlerMethodFactory() {
		DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
		factory.setValidator(myValidator());
		return factory;
	}
}

响应管理

现有支持MessageListenerAdapter已经让你的方法具有非void返回类型。在这种情况下,结果 调用封装在jakarta.jms.Message,在指定的目标中发送 在JMSReplyTo原始消息的标头或配置在 听众。现在,您可以使用@SendTo的注释 消息传递抽象。spring-doc.cadn.net.cn

假设我们的processOrder方法现在应该返回一个OrderStatus,我们可以写它 自动发送响应,如以下示例所示:spring-doc.cadn.net.cn

@JmsListener(destination = "myDestination")
@SendTo("status")
public OrderStatus processOrder(Order order) {
	// order processing
	return status;
}
如果您有多个@JmsListener-annotated 方法,也可以将@SendTo类级别的注释以共享默认回复目的地。

如果需要以与传输无关的方式设置其他标头,可以返回Message相反,使用类似于以下的方法:spring-doc.cadn.net.cn

@JmsListener(destination = "myDestination")
@SendTo("status")
public Message<OrderStatus> processOrder(Order order) {
	// order processing
	return MessageBuilder
			.withPayload(status)
			.setHeader("code", 1234)
			.build();
}

如果需要在运行时计算响应目标,可以封装响应 在JmsResponse实例,该实例还提供运行时使用的目标。我们可以重写之前的 示例如下:spring-doc.cadn.net.cn

@JmsListener(destination = "myDestination")
public JmsResponse<Message<OrderStatus>> processOrder(Order order) {
	// order processing
	Message<OrderStatus> response = MessageBuilder
			.withPayload(status)
			.setHeader("code", 1234)
			.build();
	return JmsResponse.forQueue(response, "status");
}

最后,如果您需要为响应指定一些 QoS 值,例如优先级或 Time to live,您可以配置JmsListenerContainerFactory因此 如以下示例所示:spring-doc.cadn.net.cn

@Configuration
@EnableJms
public class AppConfig {

	@Bean
	public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
		DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
		factory.setConnectionFactory(connectionFactory());
		QosSettings replyQosSettings = new QosSettings();
		replyQosSettings.setPriority(2);
		replyQosSettings.setTimeToLive(10000);
		factory.setReplyQosSettings(replyQosSettings);
		return factory;
	}
}