01 | 使用 KafkaTemplate 集成 Kafka
与 JdbcTemplate 和 RestTemplate 类似,Spring Boot 作为一款支持快速开发的集成性框架,同样提供了一批以 -Template 命名的模板工具类用于实现消息通信。
对于 Kafka 而言,这个工具类就是 KafkaTemplate。
使用 KafkaTemplate 发送消息
引入依赖:
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
KafkaTemplate 提供了一系列 send 方法用来发送消息,典型的 send 方法定义如下代码所示:
@Override
public ListenableFuture<SendResult<K, V>> send(String topic, @Nullable V data) {
}
使用 @KafkaListener 注解消费消息
Kafka 的消费者在消费消息时,需要提供一个监听器(Listener)对某个 Topic 实现监听,从而获取消息。
在 Spring 中提供了一个 @KafkaListener 注解实现监听器,该注解定义如下代码所示:
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@MessageMapping
@Documented
@Repeatable(KafkaListeners.class)
public @interface KafkaListener {
String id() default "";
String containerFactory() default "";
//消息 Topic
String[] topics() default {};
//Topic 的模式匹配表达式
String topicPattern() default "";
//Topic 分区
TopicPartition[] topicPartitions() default {};
String containerGroup() default "";
String errorHandler() default "";
//消息分组 Id
String groupId() default "";
boolean idIsGroup() default true;
String clientIdPrefix() default "";
String beanRef() default "__listener";
}
使用 @KafkaListener 注解时,我们把它直接添加在处理消息的方法上即可,如下代码所示:
@KafkaListener(topics = “demo.topic”)
public void handlerEvent(DemoEvent event) {
//TODO:添加消息处理逻辑
}
此外,还需要在消费者的配置文件中指定用于消息消费的配置项:
spring:
kafka:
bootstrap-servers:
- localhost:9092
template:
default-topic: demo.topic
consumer:
group-id: demo.group
02 | 使用 JmsTemplate 集成 ActiveMQ
JMS 规范
JMS 规范提供了一批核心接口供开发人员使用,而这些接口构成了客户端的 API 体系,如下图所示:
JMS 规范存在 ActiveMQ、WMQ、TIBCO 等多种第三方实现方式,其中较主流的是 ActiveMQ。
针对 ActiveMQ,目前有两个实现项目可供选择,一个是经典的 5.x 版本,另一个是下一代的 Artemis。
使用 JmsTemplate 集成 ActiveMQ
引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-artemis</artifactId>
</dependency>
ActiveMQ 消费方式有推送型消费者(Push Consumer)和拉取型消费者(Pull Consumer)。
使用 JmsTemplate 发送消息
JmsTemplate 中存在一批 send 方法用来实现消息发送,如下代码所示:
@Override
public void send(MessageCreator messageCreator) throws JmsException {
}
@Override
public void send(final Destination destination, final MessageCreator messageCreator) throws JmsException {
}
@Override
public void send(final String destinationName, final MessageCreator messageCreator) throws JmsException {
}
这些方法提供了一个用于创建消息对象的 MessageCreator 接口。通过 send 方法发送消息的典型实现方式如下代码所示:
public void sendDemoObject(DemoObject demoObject) {
jmsTemplate.send("demo.queue", new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
return session.createObjectMessage(demoObject);
}
}
JmsTemplate 还提供了一组更为简便的方法实现消息发送,即 convertAndSend 方法,如下代码所示:
public void sendDemoObject(DemoObject demoObject) {
jmsTemplate.convertAndSend("demo.queue", demoObject, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws JMSException {
//针对 Message 的处理
return message;
}
});
使用 JmsTemplate 消费消息
我们先来看一下如何实现拉取型消费模式。
在 JmsTemplate 中提供了一批 receive 方法供我们从 artemis 中拉取消息,如下代码所示:
public Message receive() throws JmsException {
}
public Message receive(Destination destination) throws JmsException {
}
public Message receive(String destinationName) throws JmsException {
}
推模式下的消息消费方法,如下代码所示:
@JmsListener(queues = “demo.queue”)
public void handlerEvent(DemoEvent event) {
//TODO:添加消息处理逻辑
}
03 | 使用 RabbitTemplate 集成 RabbitMQ
AMQP(Advanced Message Queuing Protocol)是一个提供统一消息服务的应用层标准高级消息队列规范。
AMQP 规范
在 AMQP 规范中存在三个核心组件,分别是交换器(Exchange)、消息队列(Queue)和绑定(Binding)。
如果存在多个 Queue,Exchange 如何知道把消息发送到哪个 Queue 中呢?
消息中包含一个路由键(Routing Key),它由消息发送者产生,并提供给 Exchange 路由这条消息的标准。而 Exchange 会检查 Routing Key,并结合路由算法决定将消息路由发送到哪个 Queue 中。
上图中,不同的路由算法存在不同的 Exchange 类型,AMQP 规范中指定了直接式交换器(Direct Exchange)、广播式交换器(Fanout Exchange)、主题式交换器(Topic Exchange)和消息头式交换器(Header Exchange)。
使用 RabbitTemplate 发送消息
引领依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
配置 RabbitMQ 服务器的地址、端口、用户名和密码等信息,如下代码所示:
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: DemoHost
在与业务代码进行集成时,我们需要将业务对象转换为 Message 对象,示例代码如下所示:
public void sendDemoObject(DemoObject demoObject) {
MessageConverter converter = rabbitTemplate.getMessageConverter();
MessageProperties props = new MessageProperties();
Message message = converter.toMessage(demoObject, props);
rabbitTemplate.send("demo.queue", message);
}
也可以使用 RabbitTemplate 的 convertAndSend 方法组进行实现,如下代码所示:
public void sendDemoObject(DemoObject demoObject) {
rabbitTemplate.convertAndSend("demo.queue", demoObject);
}
有时候我们需要在消息发送的过程中为消息添加一些属性,如下代码所示:
rabbitTemplate.convertAndSend(“demo.queue”, event, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
//针对 Message 的处理
return message;
}
});
使用 RabbitTemplate 消费消息
在拉模式下,使用 RabbitTemplate 的典型示例如下代码所示:
public DemoEvent receiveEvent() {
return (DemoEvent) rabbitTemplate.receiveAndConvert(“demo.queue”);
}
推模式的实现方法也很简单,如下代码所示:
@RabbitListener(queues = "demo.queue")
public void handlerEvent(DemoEvent event) {
//TODO:添加消息处理逻辑
}