本文翻译自 Spring Boot 官方文档 -32.Messaging
Spring 框架对整合消息系统提供了大量的支持:从简单的JMS API使用到使用 JmsTemplate
来完成接受异步消息的基础框架。Spring AMQP 为‘Advanced Message Queuing Protocol’提供了相同的特性集,Spring Boot也为RabbitTemplate
和RabbitMQ提供了自动配置项。我们在Spring WebSocket中支持原生的STOMP消息,而且Spring Boot通过Starters和少量的自动配置为其提供支持。Spring Boot也支持Apache Kafka。
javax.jms.ConnectionFactory
接口提供了创建javax.jms.Connection
标准方法来和JMS broker互相通讯。尽管Spring需要一个 ConnectionFactory
来和JMS协作,但是通常你不需要直接使用它,完全可通过上层的消息封装代替操作(详见Spring框架参考手册的相关章节)。Spring Boot给发送和接受消息的必要基础组件提供了自动配置。
Spring Boot会在类路径上发现ActiveMQ可用时配置一个ConnectionFactory
。如果存在中间件,一个内部的中间件会自动启动并被配置(只要配置中没有指定中间件URL)。
| 如果你在使用
spring-boot-starter-activemq
,连接所必需的依赖或内嵌的ActiveMQ实例会被提供,以及与JMS整合的Spring基础结构。
ActiveMQ配置由外部的在spring.activemq.*
中的配置属性控制。例如,你可在application.properties
中声明下面的部分:
spring.activemq.broker-url=tcp://192.168.1.210:9876
spring.activemq.user=admin
spring.activemq.password=secret
你可以通过给org.apache.activemq:activemq-pool
增加依赖并配置PooledConnectionFactory
因此:
spring.activemq.pool.enable=true
spring.activemq.pool.max-connections=50
| 查看
ActiveMQProperties
获取更多支持选项。你也可注册任意数量的实现ActiveMQConnectionFactoryCustomizer
的beans获得更多高级定制。
默认ActiveMQ会在队列不存在时创建一个,以便根据他们提供的名字来转变。
Spring Boot会在类路径上发现Artemis时自动配置一个ConnectionFactory
。如果broker存在,一个内部的broker会自动启动和配置(除非这模型属性被明确设置)。支持的模型有:embedded
(要明确请求的是内部broker并在类路径上没有可用的broker时引导到一个错误上),和native
使用netty
传输协议连接到一个broker。当配置后者时,Spring Boot配置一个ConnectionFactory
连接到一个使用默认设置运行在本地机器上的broker。
| 如果你正在使用
spring-boot-starter-artemis
连接到一个存在的Artemis实例的必须依赖将被提供,此外Spring会和JMS整合为基础架构。给你的应用增加org.apache.activemq:artemis-jms-server
允许你使用内部的模型。
Artemis 配置由spring.artemis.*
中的外部配置属性控制。例如,你可能在application.properties
声明了以下部分:
spring.artemis.mode=native
spring.artemis.host=192.168.1.210
spring.artemis.port=9876
spring.artemis.user=admin
spring.artemis.password=secret
因为内置了broker,你可以选择是否开启持久态和可用终点列表。使用逗号分隔的列表会使用默认选项创建,或者你可以定义类型为org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration
或org.apache.activemq.artemis.jms.server.config.TopicConfiguration
的bean(s) 分别用于高级队列和主题配置。
查看ArtemisProperties
获得更多支持的操作。
JNDI查找没有参与这些工作,destinations根据他们自己的名字来解决,即可使用Artemis配置中的‘name’属性,也可通过配置提供名称。
如果你在应用服务器上运行你的应用,Spring Boot会尝试使用JNDI定位一个JMS的ConnectionFactory
。默认检查Java:/JmsXA
和java:/XAConnectionFactory
位置。如果需要制定其他位置,你可以使用spring.jms.jndi-name
属性:
spring.jms.jndi-name=java:/MyConnectionFactory
Spring的JMSTemplate
是自动配置的,你可以在你的beans中直接自动装配。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final JmsTemplate jmsTemplate;
@Autowired
public MyBean(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
// ...
}
|
JmsMessageTemplate
可使用类似的方式注入。如果DestinationResolver
或MessageConverter
beans被定义,他们将根据自动配置的JmsTemlate
自动适应。
当JMS基础组件存在时,任何bean可使用@JmsListenter
注解来创建一个监听端点。如果没有JMSListenerConnectionFactory
被定义,默认的那个会自动配置。如果 DestinationResolver
或 MessageConverter
beans 被定义,他们会根据默认的工厂自动适应。
通常,默认的工厂是事务性的。如果你在一个存在JtaTransactionManager
的基础框架上,它将关联默认的监听容器。如果不存在,sessionTransacted
标识位将可用。对于后者,你可以在你的监听方法(或委派它的代表)上增加@Transactional
来将你本地的数据存储事务交给进来的消息处理。请确保进来的消息在本地事务完成时知晓。这还包括在同一JMS回话上执行响应的消息。
下面的组件在someQueue
目的节点创建一个监听:
@Component
public class MyBean {
@JmsListener(destination = "someQueue")
public void processMessage(String content) {
// ...
}
}
| 查看
@EnableJms
的javadoc获得更多细节
如果你想创建更多的 JmsListenerContainerFactory
实例或者你想重写默认的,Spring Boot提供DefaultJmsListenerContainerFactoryConfigurer
让你用来初始化一个和自动配置相同设置的DefaultJmsListenerContainerFactory
。
例如,下面的例子期望另一个工厂使用指定的MessageConverter
:
@Configuration
static class JmsConfiguration {
@Bean
public DefaultJmsListenerContainerFactory myFactory(
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
configurer.configure(factory, connectionFactory());
factory.setMessageConverter(myMessageConverter());
return factory;
}
}
然后你可以像下面一样使用任何@JmsListener
注解的方法:
@Component
public class MyBean {
@JmsListener(destination = "someQueue", containerFactory="myFactory")
public void processMessage(String content) {
// ...
}
}
高级消息队列协议(AMQP)是一个中立平台,为面向消息的中间件线级协议。Spring AMQP工程是应用Spring核心概念来开发基于AMQP的消息解决方案。Spring Boot通过RabbitMQ为和AMQP工作提供了一些便利,这些包含在spring-boot-starter-amqp
起步器中。
RabbitMQ是一个轻量,可靠,可拓展和易用的基于AMQP协议的消息中间件。Spring使用RabbitMQ
来使用AMQP协议通讯。
RabbitMQ配置被在外部spring.rabbitmq.*
中的配置属性控制。例如,你可能在application.properties
中声明了下面的部分:
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret
查看RabbitProperties
获得更多支持操作。
| 查阅 Understanding AMQP, the protocol used by RabbitMQ 获得更多详情。
Spring的AmqpTemplate
和AmqpAdmin
被自动配置,你可直接在你的beans中自动装配他们:
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final AmqpAdmin amqpAdmin;
private final AmqpTemplate amqpTemplate;
@Autowired
public MyBean(AmqpAdmin amqpAdmin, AmqpTemplate amqpTemplate) {
this.amqpAdmin = amqpAdmin;
this.amqpTemplate = amqpTemplate;
}
// ...
}
|
RabbitMessagingTemplate
可以同样的方式注入。如果定义了MessageConverter
,它会自动适应自动配置的AmqpTemplate
。
任何org.springframework.amqp.core.Queue
被定义为一个bean都将自动用于在RabbitMQ实例上必要时声明适当的队列。
你可以开启AmqpTemplate
的重试来重复操作,例如在中间件连接丢失事件上的重连。默认重试是禁用的。
在Rabbit组件存在时,任何bean都可以使用@RabbitListener
注解来创建一个监听节点。如果没有RabbitListenerContainerFactory
被定义,默认的bean会被自动配置。如果MessageConverter
或 MessageRecoverer
beans被定义,他们会自动适应默认的工厂。
下面的组件,在someQueue
队列上创建一个监听终端:
@Component
public class MyBean {
@RabbitListener(queues = "someQueue")
public void processMessage(String content) {
// ...
}
}
| 查阅
@EnableRabbit
的Java手册 获得更多细节。
如果你需要创建更多的’RabbitListenerContainerFactory’实例或你想重写默认的,Spring Boot 提供一个SimpleRabbitListenerContainerFactoryConfigurer
以便你可以用来初始化一个和自动配置相同设置的SimpleRabbitListenerContainerFactory
。
例如,下面展示了使用特定MessageConverter
的另一个工厂;
@Configuration
static class RabbitConfiguration {
@Bean
public SimpleRabbitListenerContainerFactory myFactory(
SimpleRabbitListenerContainerFactoryConfigurer configurer) {
SimpleRabbitListenerContainerFactory factory =
new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
factory.setMessageConverter(myMessageConverter());
return factory;
}
}
然后想下面一样用在任何@RabbitListener
注解的方法上:
@Component
public class MyBean {
@RabbitListener(queues = "someQueue", containerFactory="myFactory")
public void processMessage(String content) {
// ...
}
}
你可以开启重试来处理你的监听器在哪里抛出异常的情况。默认使用的RejectAndDontRequeueRecoverer
除非定义了你自己的MessageRecoverer
。当重试次数用尽,消息将被拒绝,或删除,或发送给私信交换在Broker这样配置时。重试默认是禁用的。
| Important
如果重试次数未开启,监听器抛出了异常,通常传递会无限次的重试。你可以用两种方式修改此行为;设置defaultRequeueRejected
属性为false
将尝试零重交付;或抛出一个AmqpRejectAndDontRequeueException
给拒绝消息的信号。这些是用在重试开启并在达到最大尝试次数时的使用技巧。
Apache Kafka 的支持是通过提供spring-kafka
工程的自动配置实现的。
Kafka配置由spring.kafka.*
中的配置属性控制。例如,你在application.properties
中配置了下面的部分:
spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.consumer.group-id=myGroup
查看KafkaProperties
获得更多支持操作。
Spring的KafkaTemplate
是自动配置的,你可以直接自动装配他们到你的beans中:
@Component
public class MyBean {
private final KafkaTemplate kafkaTemplate;
@Autowired
public MyBean(KafkaTemplate kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
// ...
}
Apache Kafka组件存在时,任何bean可以使用@KafkaListener
注解来创建一个监听终端。如果KafkaListenerContainerFactory
没被定义,默认的工厂会使用定义在spring.kafka.listener.*
中的键自动配置。
下面组件在someTopic
规则上创建一个监听终端:
@Component
public class MyBean {
@KafkaListener(topics = "someTopic")
public void processMessage(String content) {
// ...
}
}
自动配置支持的属性显示在 [Appendix A, Common application properties](Appendix A, Common application properties).注意这些属性(连字符连接的 或驼峰式)大部分直接对应到Apache Kafka点分隔的属性。详细对照Apache Kafka文档。
这些属性中的前几个应用于生产者和消费者,但如果你希望分别为他们使用不同的值,则可以在生产者或消费者基表指定。Apache Kafka指定属性附带价值:高、中和低。Spring Boot自动配置支持所有的高级,少数可选的中级和低级 和任何没有默认值的属性。
仅一些Kafka支持的属性子集可通过KafkaProperties
类获得。如果你希望给生产者或消费者配置额外不直接支持的属性,使用下述属性:
spring.kafka.properties.foo.bar=baz
该设置设置公共foo.bar
Kafka属性为baz
。
这些属性将被生产者和消费者工厂beans共享。如果你希望定制这些组件使用不同的属性,只需为每一个使用不同的度量读入器,你可以像下面一样重写这个bean的定义:
@Configuration
public static class CustomKafkaBeans {
/**
* Customized ProducerFactory bean.
* @param properties the kafka properties.
* @return the bean.
*/
@Bean
public ProducerFactory, ?> kafkaProducerFactory(KafkaProperties properties) {
Map producerProperties = properties.buildProducerProperties();
producerProperties.put(CommonClientConfigs.METRIC_REPORTER_CLASSES_CONFIG,
MyProducerMetricsReporter.class);
return new DefaultKafkaProducerFactory