微服务专题13-Spring Cloud Stream (上)

前言

前面的章节我们讲了Spring Cloud Gateway

本节,继续微服务专题的内容分享,共计16小节,分别是:

本节内容重点为:

  • RabbitMQ
  • Spring RabbitMQ
  • Spring Boot RabbitMQ

Spring Cloud Stream 相关技术

Spring Cloud Stream 是一个用来为微服务应用构建消息驱动能力的框架。它可以基于 Spring Boot 来创建独立的、可用于生产的 Spring 应用程序。Spring Cloud Stream 为一些供应商的消息中间件产品提供了个性化的自动化配置实现,并引入了发布-订阅、消费组、分区这三个核心概念。通过使用 Spring Cloud Stream,可以有效简化开发人员对消息中间件的使用复杂度,让系统开发人员可以有更多的精力关注于核心业务逻辑的处理。在这里插入图片描述

以Java8 Stream流为例:

        Stream
                .of(1, 2, 3, 4, 5)                         // 生产
                .map(String::valueOf)               // 处理
                .forEach(System.out::println);  // 消费

这里一共出现了三种身份:

  • Publisher:生产者

  • Subscriber:处理者

  • Processor:消费者

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qFl8tsgR-1597760291411)(assets/1534339046352.png)]

元编程:就是基于编程的编程、比如像反射Reflection、函数式编程Function、Lambda表达式、表达式语言即${user.age}

Spring Cloud Data Flow

区别于,上面提到的steam流处理, Spring Cloud Data Flow以应用为单位,实现生产,处理,消费这三个过程的!

在这里插入图片描述

每个进程之间应该有这不同的进程结束号,使用System.exit(N) ,N值为可变整数,加以区分不同进程。

Spring Cloud Stream 整合 RabbitMQ

我们这里使用本专题之前已经搭建好的项目:

  • spring-cloud-client-application
  • spring-cloud-server-application

在此基础上对RabbitMQ做技术实现:
在这里插入图片描述

1、pom依赖配置。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>

2、 配置项。

我们参考源码:org.springframework.cloud.stream.binder.rabbit.properties.RabbitBindingProperties 不难发现,通过以下配置实现SpringCloud与rabbitmq 的双向绑定:

## IP、端口、用户名、密码、虚拟主机
## 默认使用 / 的vhost,如果修改vhost,加在端口后即可,如 /testhost
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

# Spring Cloud Stream 配置
## 驱动的名字是 test2020
## spring.cloud.stream.bindings.${channel-name}.destination
## destination = topic
spring.cloud.stream.bindings.test2020.binder = rabbit
spring.cloud.stream.bindings.test2020.destination = test2020

小技巧,学习语言,要掌握一通百通的道理,源码设计者也是通过前人不断总结的经验不断地完善模型,比如Spring 中各种 xxxTemplate 实现 的xxxOperations就是如此:

  • JdbcTemplate:Spring 操作 jdbc连接数据库。
  • RedisTemplate:Spring操作redis连接缓存数据库。
  • RabbitTemplate:Spring操作rabbit连接消息中间件。
  • KafkaTemplate:Spring操作kafka连接消息中间件。
  • RestTemplate:Spring封装http请求进行远程调用。

3、客户端与服务端实现rabbitmq消息通信。

客户端配置

使用 MessageChannel 封装请求

public interface SimpleMessageService {

    @Output("test2020") // Channel name
    MessageChannel test(); //  destination = test2020
}

编写客户端api:

@RestController
public class MessageController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private SimpleMessageService simpleMessageService;

    @GetMapping("/stream/send")
    public boolean streamSend(@RequestParam String message) {
        // 获取 MessageChannel
        MessageChannel messageChannel = simpleMessageService.test();
        Map<String, Object> headers = new HashMap<>();
        headers.put("charset-encoding", "UTF-8");
        headers.put("content-type", MediaType.TEXT_PLAIN_VALUE);
        return messageChannel.send(new GenericMessage(message, headers));
    }
}

紧接着,启动项激活并引入 SimpleMessageService:

@EnableBinding(SimpleMessageService.class) // 激活并引入 SimpleMessageService

服务端配置

类似地,使用 SubscribableChannel 封装接收类:

public interface SimpleMessageReceiver {

    @Input("test2020")
    SubscribableChannel test();
}

紧接着,启动类激活并引入 SimpleMessageReceiver:

@EnableBinding(SimpleMessageReceiver.class) // 激活并引入 SimpleMessageReceiver

然后,务必在消息处理中做幂等性处理:

    @Autowired
    private SimpleMessageReceiver simpleMessageReceiver;

	@PostConstruct
    public void init() {  // 接口编程
        // 获取 SubscribableChannel
        SubscribableChannel subscribableChannel = simpleMessageReceiver.gupao();
        subscribableChannel.subscribe(message -> {
            MessageHeaders headers = message.getHeaders();
            String encoding = (String) headers.get("charset-encoding");
            String text = (String) headers.get("content-type");
            byte[] content = (byte[]) message.getPayload();
            try {
                System.out.println("接受到消息:" + new String(content, encoding));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        });
    }

    @StreamListener("test2020")  // Spring Cloud Stream 注解驱动
    public void onMessage(byte[] data) {
        System.out.println("onMessage(byte[]): " + new String(data));
    }

    @StreamListener("test2020")  // Spring Cloud Stream 注解驱动
    public void onMessage(String data) {
        System.out.println("onMessage(String) : " + data);
    }

    @StreamListener("test2020") // Spring Cloud Stream 注解驱动
    public void onMessage2(String data2) {
        System.out.println("onMessage2(String) : " + data2);
    }

    @ServiceActivator(inputChannel = "test2020") // Spring Integration 注解驱动
    public void onServiceActivator(String data) {
        System.out.println("onServiceActivator(String) : " + data);
    }

注意:相同的编程模型重复执行,例如 @StreamListener,不同的编程模型轮流执行

5、启动并测试

分别启动, spring-cloud-client-application项目、spring-cloud-server-application项目、zookeeper服务与rabbitmq服务,rabbitmq服务搭建可以参考本人往期rabbitmq博客

现在我们访问:
http://localhost:8888/stream/send?message=test
在这里插入图片描述
访问RabbitMQ管理页面:
在这里插入图片描述

后记

本节代码地址:Spring Cloud Steam

更多架构知识,欢迎关注本套Java系列文章Java架构师成长之路

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值