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 体系,如下图所示:


spring cloud stream kafka 整合_spring

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 中。


spring cloud stream kafka 整合_ide_02

上图中,不同的路由算法存在不同的 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:添加消息处理逻辑
}