微服务之消息驱动Stream

霸气de小男生 提交于 2019-12-22 10:54:09
消息驱动:

事件驱动架构(Event Driven Architecture)EDA
消息驱动架构(Message Driven Architecture)MDA
我们日常生活就是消息驱动的

springCloud stream使得构建基于消息传递的解决方案变得轻而易举,springCloud stream的目的是隔离具体的消息中间件,而使得各种消息中间件可以保持统一的编码

用许可证服务和组织服务举例:

许可证服务会调用组织服务的接口,为了加快程序响应速度,我们需要在许可证服务缓存组织服务的一部分数据,但是也需要在组织服务的这部分数据发生改变的时候,及时同步新的数据
使用消息驱动,意味着许可证服务和组织服务之间加入了一个消息队列,当组织服务的数据发生改变的时候,会向消息对垒发布一个消息,许可证服务监听队列中由组织服务发布的所有消息,并且根据需要使本地缓存数据失效

消息队列充当中介:

这种使用消息队列充当许可证服务和组织服务之间中介的方法有以下好处:

  • 松耦合,两个服务都不知道彼此
  • 耐久性,即使服务的消费者已经关闭,也可以发送消息
  • 可伸缩性,可以启动更多的消息消费者来处理队列中的嘻嘻
  • 灵活性,消息的发送者不知道谁将消费它,这意味着可以轻松添加新的消费者

缺点是:

  • 消息处理语义,如果要求消息按照时间顺序消费怎么处理,如果消息结构发生变化怎么处理,如果消息处理失败怎么办
  • 消息可见性,消息的异步性,改变的消息通常不会立即被接收或者处理
  • 消息编排,基于消息传递的应用更难按照应用程序的执行顺序进行业务逻辑推理

但是以上缺点并不是要在应用程序中远离消息传递,而是需要在使用消息传递的时候更深谋远虑

spring cloud stream架构:

1.发射器:发射器是一个spring注解接口,接收一个java对象,该对象代表发布的消息,发射器序列化该对象并将消息发布到通道
2.通道:通道是对队列的一个抽象,通道名称始终与队列名称相关,在代码中使用的就是通道名称
3.绑定器:spring cloud stream框架的一部分,是特定消息平台与spring对话对的代码
4.接收器:在spring中服务通过接收器队列从队列中接收消息,并将消息反序列化为POJO,然后交给业务逻辑进行处理

用于发布消息的配置:
spring:
  cloud:
    stream:
      bindings:
        output:
            destination:  orgChangeTopic
            content-type: application/json
      kafka:
        binder:
          zkNodes: localhost
          brokers: localhost

bindings 是所需配置的开始,用于服务吧消息发布到stream消息代理
output 是通道的名称,映射到代码上的sourc.output()通道
destination 是要写入消息的消息队列的名称,这里的生产者的消息队列需要和消费者的消息队列一致
content-type 向spring cloud stream声明将要发送和接收什么类型的消息
kafka 属性告诉spring,将使用kafka作为服务中的消息总线
zknodes 和 brokers 属性告诉 spring ,kafka和zookeeper的网络

编写消息消费者:

1.添加maven依赖

spring-cloud-stream
spring-cloud-starter-stream-kafka

2.使用spring cloud stream绑定到消息代理,同样给springboot启动类添加注解@EnableBinding(Sink.class),此注解告诉spring使用sink接口定义的通道来监听传入的消息
3.使用@StreamListener注解监听指定的通道,代码如下所示:

@StreamListener(Sink.INPUT)
public void loggerSink(OrganizationChangeModel orgChange) {
    logger.debug("Received an event for organization id {}", orgChange.getOrganizationId());
}

@StreamListener注解表明,每次收到来自 input通道的消息时,spring cloud stream 将执行此方法,方法的参数就是消息体反序列化得到的POJO
4.在配置文件application.yml中配置消息,如下所示:

spring:
  cloud:
    stream:
      bindings:
        input:
          destination: orgChangeTopic
          content-type: application/json
          group: licensingGroup
      kafka:
        binder:
          zkNodes: localhost
          brokers: localhost

bindings 是所需配置的开始
input是通道的名称
destination 将通道映射到消息队列,这里的消费者的消息队列需要和消息生产者的消息队列一致
group 消费者组,同一组消费者针对某一条消息,只会有一个组员接收
content-type 向spring cloud stream声明将要发送和接收什么类型的消息
kafka 属性告诉spring,将使用kafka作为服务中的消息总线
zknodes 和 brokers 属性告诉 spring ,kafka和zookeeper的网络位置

自定义消息通道:

public interface CustomChannels {
    //通过input公开的消息通道必须返回一个 SubscribableChannel类
    @Input("inboundOrgChanges")
    SubscribableChannel orgs();
}

然后修改application.yml里面的input为inboundOrgChanges即可

Stream发送消息:

1.通过消息管道发送消息:MessageChannel,source是messageChannel的代理类
2.通过spring Kafka模板类发送消息:KafkaTemplate (Kafka独有)
使用messageChannel发送消息如下所示:

 @Autowired
    private Source source;
    @Autowired
    private MessageSource messageSource;

    @Autowired
    @Qualifier(MessageSource.OUTPUT) // Bean 名称
    private MessageChannel gupaoMessageChannel;
    // 发送消息
    public void send(String message){
        // 通过消息管道发送消息
        source.output().send(MessageBuilder.withPayload(message).build());
    }

    // 发送消息到 Gupao
    public void sendToGupao(String message){
        // 通过消息管道发送消息
        gupaoMessageChannel.send(MessageBuilder.withPayload(message).build());
    }

Stream客户端接收消息:

1.通过订阅管道接收消息:SubscribableChannel,Sink是SubscribableChannel的代理类(标准Sink监听)
2.使用注解PostConstruct,ServiceActivator,StreamListener接收指定主题的消息

1.标准Sink监听:
通过SubscribableChannel监听指定通道,如下所示:

@Autowired
@Qualifier(Sink.INPUT) // Bean 名称
private SubscribableChannel subscribableChannel;

// 当字段注入完成后的回调
@PostConstruct
public void init() {
    // 实现异步回调,订阅指定通道
    subscribableChannel.subscribe(new MessageHandler() {
        @Override
        public void handleMessage(Message<?> message) throws MessagingException {
            System.out.println("subscribe : " + message.getPayload());
        }
    });
}

2.ServiceActivator监听(Spring Integration注解驱动)

//通过@ServiceActivator
@ServiceActivator(inputChannel = Sink.INPUT)
public void onMessage(Object message) {
    System.out.println("@ServiceActivator : " + message);
}

3.StreamListener监听(SpringCloud Stream注解驱动)

@StreamListener(Sink.INPUT)
public void onMessage(String message){
    System.out.println("@StreamListener : " + message);
}

Kafka独有的消息接收监听:
4.KafkaListener监听:

@KafkaListener(topics ="${kafka.topic}")
public void onMessage(String message) {
    System.out.println("Kafka 消费者监听器,接受到消息:" + message);
}

上面四种编程模型,不同的编程模型在接收消息的时候轮流接收消息,重复的编程模型全部接收消息(例如:StreamListener监听相同的通道)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!