spring cloud stream

介绍

目前stream封装了RabbitMq、kafka和redis消息组件,基于SpringBoot实现自动化配置,用户只需要使用stream的api,就可以通用的使用stream支持的各个消息组件。

 

 

 

原理

主要的概念是Channel和Binder。

生产者:消息发送到Channel,然后经过Binder转化成对应的消息组件操作。

消费者:通过binder获取到消息然后转化成对应的stream消息到Channel,然后消费者消费Channel消息。

 

 

 

实践

使用RabbitMq消息组件,以下是生产者代码

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>streamtest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>streamtest</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

 

配置文件application.yml

server:
  port: 9000
spring:
  application:
    name: stream-producer
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

 

创建一个接口定义通道

package com.example.streamtest;

import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;


public interface SendMessageInterface {

    /**
     * 创建一个输出通道,用于发送消息
     * @return
     */
    @Output("my_msg")
    MessageChannel sendMsg();
}

 

 

Controller层发送消息

package com.example.streamtest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SendController {
    @Autowired
    private SendMessageInterface sendMessageInterface;

    @RequestMapping("/send")
    public String sendMsg(){
        Message message = MessageBuilder.withPayload("this is message".getBytes()).build();
        sendMessageInterface.sendMsg().send(message);
        return "ok";
    }
}

 

 

springboot入口类

package com.example.streamtest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;

@SpringBootApplication
@EnableBinding(SendMessageInterface.class)
public class StreamtestApplication {

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

}

 

启动项目

打开rabbit管理系统http://localhost:15672

可以发现创建了名为my_msg的topic

 

 

 

创建消费者项目

以下是消费者的代码

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>streamconsumertest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>streamconsumertest</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

 

 

配置文件application.yml

server:
  port: 9001
spring:
  application:
    name: stream-consumer
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

 

 

创建接口定义通道

package com.example.streamconsumertest;

import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;

public interface ReceiveMsgInterface {

    /**
     * 从通道获取消息
     * @return
     */
    @Input("my_msg")
    SubscribableChannel receiveMeg();
}

 

 

创建监听消息类

package com.example.streamconsumertest;

import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.stereotype.Component;

@Component
public class Consumer {

    @StreamListener("my_msg")
    public void listener(String msg){
        System.out.println("消费消息:"+msg);
    }
}

 

 

springboot入口类

package com.example.streamconsumertest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;

@SpringBootApplication
@EnableBinding(ReceiveMsgInterface.class)
public class StreamconsumertestApplication {

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

}

 

 

启动消费者项目

在RabbitMq管理系统可以看到创建了一个消息队列

这个消息队列名称是strema自动生成的。

 

 

用浏览器访问http://localhost:9000/send发送消息

可以看到消费者项目的控制台打印了一条消息

说明成功消费到了消息。

 

 

 

 

多个消费者重复消费同一个消息问题

修改消费者项目为可以启动多个

 

 

然后修改消费者项目端口号为9002,然后再次启动一次项目,这样消费者项目就开启了两个,一个端口号是9001,一个端口号是9002.

在RabbitMq管理系统中可以看见又创建了一个队列

 

在浏览器再次访问http://localhost:9000/send发送消息

 

发现两个消费者都消费到了消息。

但是一般现在的微服务为了实现高可用都会进行集群部署,消息被重复消费两次是不合理的,为了解决这个问题。

可以修改消费者配置文件application.yml

server:
  port: 9002
spring:
  application:
    name: stream-consumer
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
  cloud:
    stream:
      bindings:
        my_msg:  #指定管道名称
          group: myGroup   #指定该应用实例属于myGroup消费组

这样就指定了一个消费者组,类似kafka的消费者组概念,一个消费者组中只能有一个消费者消费同一个消息。

 

再次启动两个消费者项目。

可以在RabbitMq管理系统中看到

只创建了一个队列,而且这个队列就算关闭项目之后也会继续存在,不像之前stream创建的随机名称的队列,会在关闭项目之后队列消失。

 

 

在浏览器再次访问http://localhost:9000/send发送消息

可以发现两个消费者中只有一个消费者消费到了消息,多次发送消息之后,可以发现,多个消费者是轮询着消费消息的。

 

 

 

 

更改项目环境为kafka

不需要更改代码,只需要更改配置文件

修改生产者和消费者pom依赖修改stream-rabbit为stream-kafka

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-stream-kafka</artifactId>
	<version>2.0.1.RELEASE</version>
</dependency>

 

 

修改生产者配置文件

server:
  port: 9000
spring:
  application:
    name: stream-producer
  cloud:
    stream:
      # 设置成使用kafka
      kafka:
        binder:
          # Kafka的服务端列表,默认localhost
          brokers: 192.168.1.8:9092,192.168.1.9:9092,192.168.1.10:9092
          # Kafka服务端连接的ZooKeeper节点列表,默认localhost
          zkNodes: 192.168.1.8:2181,192.168.1.9:2181,192.168.1.10:2181
          minPartitionCount: 1
          autoCreateTopics: true
          autoAddPartitions: true

 

 

修改消费者配置文件

server:
  port: 9001
spring:
  application:
    name: stream-consumer
  cloud:
     instance-count: 1
     instance-index: 0
     stream:
        kafka:
          binder:
            # Kafka的服务端列表,默认localhost
            brokers: 192.168.1.8:9092,192.168.1.9:9092,192.168.1.10:9092
            # Kafka服务端连接的ZooKeeper节点列表,默认localhost
            zkNodes: 192.168.1.8:2181,192.168.1.9:2181,192.168.1.10:2181
            auto-add-partitions: true
            auto-create-topics: true
            min-partition-count: 1
        bindings:
          input:
            destination: my_msg
            group: myGroup
            consumer:
              autoCommitOffset: false
              concurrency: 1
              partitioned: false

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值