Spring Cloud Stream与Kafka(一)

Spring Cloud Stream与Kafka(一)

​ 在实际开发过程中,消息中间件用于解决应用解耦,异步消息,流量削峰等问题,实现高可用、高性能、可伸缩和最终一致性架构。不同的消息中间件实现方式不同,内部结构是不一样的。比如常见的RabbitMQ和Kafka,RabbitMQ有exchange,kafka有topic、partition,这些中间件的差异性导致我们在实际项目开发过程中造成了一定的干扰。如果采用了其中的一种,后面的业务需求,我想往另一种消息队列迁移,有一堆东西需要重做。Spring Cloud Stream是一种解耦的方式。

简单介绍

  1. Spring Cloud Stream是由一个中间件中立的核心组成,应用通过Spring Cloud Stream插入的input(相当于消费者)和output(相当于生产者)通道与外界交流。通道通过指定中间件的Binder与外部代理连接,业务开发者不需要关注具体的消息中间件,只需要关注Binder对应程序提供的抽象概念来使用中间件实现业务就可以了。Spring Cloud Stream许多抽象和原语,简化了消息驱动微服务应用程序的开发。

SCSt-with-binder

  • 最底层是消息服务,中间层是绑定层,绑定层和底层的消息服务进行绑定,顶层是消息生产者和消费者,顶层可以向绑定层生产消费、获取消息。
  1. Binder绑定器作为中间层,实现了应用程序与消息中间件细节之间的隔离。通过向应用程序暴露统一的Channel通道,使得应用程序不需要考虑具体的中间件实现。当需要升级或更换中间件产品时,我们要做的就是更换对应的Binder绑定器而不需要修改任何应用逻辑。

  2. 在Spring Cloud Stream中的消息通信方式遵循发布订阅模式,当一条消息被投递到消息中间件后,它会通过共享的主题进行广播,消费者在订阅的主题收到消息后触发自身的业务逻辑处理。这里的主题是抽象概念,代表发布共享消息给消费者的地方。在不同的消息中间中,主题可能对应着不同的概念。

  3. Destination Binders是负责提供与外部消息系统集成的组件。Destination Bindings是外部消息系统和最终用户提供的应用程序代码(生产者/消费者)之间的桥梁。Message是生产者和消费者用于与目标绑定器通信的规范化数据结构。

Kafka实例

  1. 分别创建生产者kafka-producer和消费者kafka-consumer,引入依赖。
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-stream-kafka</artifactId>
    </dependency>
</dependencies>
生产者
  1. 添加配置文件application.yml
spring:
  cloud:
    stream:
      kafka:
        binder: # 绑定器
          brokers: 192.168.182.171:9092   # broker的IP和端口
  application:
    name: kafka-provider

server:
  port: 8301
  1. 添加启动类
package org.lxx.stream.kafka.producer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class KafkaProducerApplication {

    public static void main(String[] args) {
        SpringApplication.run(KafkaProducerApplication.class, args);
    }

}
  1. 添加配置文件
package org.lxx.stream.kafka.producer.config;

import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.stereotype.Component;

@Component
public interface MyProcessor {

    String MESSAGE_OUTPUT = "log_output";

    //在Kafka中创建主题log_output
    @Output(MESSAGE_OUTPUT)
    SubscribableChannel logOutput();
}
  1. 创建实体类
package org.lxx.stream.kafka.producer.entity;

import lombok.Data;

import java.util.Date;

@Data
public class LogInfo {
    private String clientVersion;
    private String userId;
    private String clientIP;
    private Date time;
}
  1. 创建控制器
package org.lxx.stream.kafka.producer.controller;

import lombok.extern.slf4j.Slf4j;
import org.lxx.stream.kafka.producer.config.MyProcessor;
import org.lxx.stream.kafka.producer.entity.LogInfo;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.sql.Date;
import java.time.Instant;

@Slf4j
@RestController
@EnableBinding(value = {MyProcessor.class})
public class MessageController {

    @Resource
    private MyProcessor myProcessor;

    @GetMapping("sendLogMessage")
    public void sendLogMessage(String message) {
        Message<String> strMessage = 
            MessageBuilder.withPayload(message).build();
        myProcessor.logOutput().send(strMessage);
    }

    @GetMapping("sendObjLogMessage")
    public void sendObjLogMessage() {
        LogInfo logInfo = new LogInfo();
        logInfo.setClientIP("192.168.1.111");
        logInfo.setClientVersion("1.0");
        logInfo.setUserId("198663383837434");
        logInfo.setTime(Date.from(Instant.now()));
        Message<LogInfo> strMessage = 
            MessageBuilder.withPayload(logInfo).build();
        myProcessor.logOutput().send(strMessage);
    }
}
消费者
  1. 添加配置文件application.yml
spring:
  cloud:
    stream:
      kafka:
        binder: # 绑定器
          brokers: 192.168.182.171:9092   # broker的IP和端口
  application:
    name: kafka-consumer

server:
  port: 8302
  1. 添加启动类
package org.lxx.stream.kafka.consumer;

import org.lxx.stream.kafka.consumer.config.MyProcessor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;

@EnableBinding(value = MyProcessor.class)
@SpringBootApplication
public class KafkaConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(KafkaConsumerApplication.class, args);
    }

}
  1. 添加配置类
package org.lxx.stream.kafka.consumer.config;

import org.springframework.cloud.stream.annotation.Input;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.stereotype.Component;

@Component
public interface MyProcessor {

    String MESSAGE_INPUT = "log_input";
    String MESSAGE_OUTPUT = "log_output";
    String LOG_FORMAT_INPUT = "log_format_input";
    String LOG_FORMAT_OUTPUT = "log_format_output";

    @Input(MESSAGE_INPUT)
    SubscribableChannel logInput();

    @Output(MESSAGE_OUTPUT)
    SubscribableChannel logOutput();

    @Input(LOG_FORMAT_INPUT)
    SubscribableChannel logFormatInput();

    @Output(LOG_FORMAT_OUTPUT)
    SubscribableChannel logFormatOutput();

}
  1. 添加监听器
package org.lxx.stream.kafka.consumer.service;

import lombok.extern.slf4j.Slf4j;
import org.lxx.stream.kafka.consumer.config.MyProcessor;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class MessageListener {

    @StreamListener(MyProcessor.MESSAGE_INPUT)
    @SendTo(MyProcessor.LOG_FORMAT_OUTPUT)
    public String processLogMessage(String message) {
        //通过MyProcessor.MESSAGE_INPUT接收消息
        //然后通过SendTo把处理后的消息发送到MyProcessor.LOG_FORMAT_OUTPUT
        log.info("GET Message:" + message);
        return message;
    }

    @StreamListener(MyProcessor.LOG_FORMAT_INPUT)
    public void processFormatLogMessage(String message) {
        //接收来自MyProcessor.LOG_FORMAT_INPUT 的消息
        //也就是SendTo发送的加工后的消息
        log.info("接收到格式化后的消息:" + message);
    }

}
  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Cloud Stream是一个基于Spring Boot的框架,用于构建可扩展和可靠的消息驱动型微服务应用程序。而Kafka是一个分布式流媒体平台,用于构建实时数据流应用程序。 在Spring Cloud Stream中集成Kafka非常简单。首先,需要在项目的pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-binder-kafka</artifactId> </dependency> ``` 接下来,需要在项目的application.properties文件中配置Kafka的相关信息,包括Kafka服务器的地址和端口号、Topic的名称等。下面是一个示例配置: ```properties spring.cloud.stream.kafka.binder.brokers=192.168.0.1:9092 spring.cloud.stream.bindings.input.destination=my-topic spring.cloud.stream.bindings.output.destination=my-topic ``` 在上述配置中,`spring.cloud.stream.kafka.binder.brokers`指定Kafka服务器的地址和端口号,`spring.cloud.stream.bindings.input.destination`和`spring.cloud.stream.bindings.output.destination`分别指定了输入和输出的Topic名称。 然后,可以使用`@EnableBinding`注解启用绑定器并定义输入和输出的通道。例如,可以创建一个消费者类并定义一个`@Input`注解,用于接收来自Kafka Topic的消息: ```java @EnableBinding(Processor.class) public class Consumer { @StreamListener(Processor.INPUT) public void receive(String message) { System.out.println("Received message: " + message); } } ``` 类似地,可以创建一个生产者类并定义一个`@Output`注解,用于将消息发送到Kafka Topic: ```java @EnableBinding(Processor.class) public class Producer { @Autowired private MessageChannel output; public void send(String message) { output.send(MessageBuilder.withPayload(message).build()); } } ``` 以上是使用Spring Cloud Stream配置Kafka的基本步骤。通过这种方式,我们可以轻松地实现消息驱动型的微服务应用程序,并且享受到Kafka作为分布式流媒体平台的优势。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快乐江小鱼

知识创造财富,余额还是小数

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值