SpringCloud Alibaba入门教程四——服务通信与异步通信

SpringCloud Alibaba 微服务通信

Spring实现异步的方法

实现异步任务是为了使用户体验更好。

  • AsyncRestTemplate
  • @Async注解
  • WebClient(SpringClient5.0引入)
  • MQ消息队列

MQ

适用场景

  • 异步处理
  • 流量削峰填谷(防止因为人数过多,导致的服务器崩溃,达到一定限制后直接丢弃请求)
  • 解耦微服务

MQ的选择

RocketMQ 是Alibaba出品 并且贡献给了 Apache 官方,现在已经被官方纳入重点维护项目。
关于MQ的选择,其实是一门通多门,RocketMQ的好处在于RocketMQ与其他MQ对比

RocketMQ下载

详细的下载教程为如何下载安装RacketMQ

RocketMQ控制台

如何安装RocketMQ控制台,详细的介绍了如何安装RocketMQ并且适配RocketMQ版本

RocketMQ在SpringBoot中的配置

发送者

引入依赖rocketmq-spring-boot-starter,并且要适配版本(主要是适配控制台的版本,与引入的控制台版本保持一致)。

rocketmq:
  name-server: 127.0.0.1:9876
  producer:
    # 接受者组
    group: test-group 
//使用之前要将相关的实体类注入
@Autowired
private final RocketMQTemplate r;

//发送方法
r.convertAndSend("Topic的名称,自己定义","要发送的消息");

接收者

引入依赖rocketmq-spring-boot-starter,并且要适配版本(主要是适配控制台的版本,与引入的控制台版本保持一致)。

rocketmq:
  name-server: 127.0.0.1:9876
//创建一个类实现RocketMQ接口,实现onMessage方法,泛型写接收类的类型


@Service
@RocketMQMessageListener(topic = "这里写topic的名称,和生产者的一样",consumerGroup = "consumer-group")
//必须制定消费者组
public class AddBonusListener implements RocketMQlistener<T>{
  @Override
  public void onMessage(UserAddBonusMsgDTO message){
    //当收到消息后,执行具体的业务
    
  }

}

各类MQ在Java中的使用类以及注解

在这里插入图片描述
在这里插入图片描述

Rocket实现分布式事务

在这里插入图片描述

使用RocketMQ实现分布式事务

  1. 分析业务是否需要联动微服务
  2. 调用其他微服务需要异步调用还是同步调用
  3. 通过在RocketMQ中的RocketMQTraction进行分布式任务的书写

首先,使用RocketMQTemplate的sendMessageTransaction方法发送分布式事务,该方法有4个参数,第一个是需要被二次监听函数监听的名称;第二个是topic需要和接受者的一样;第三个是message,也就是传递给接受者的一样,第四个是一个留空参数,可以传递一些自己想要传递的值。

编写一个类实现RocketMQLocalTransactionListener接口,用来向Broker服务器发送二次确认的方法,其中executeLocalTransaction方法中要实现二次确认,而checkLocalTransaction方法则是在我们出现异常情况时接收端向我们发送确认消息时执行的逻辑,根据其中返回Commit还是Fallback指定是否要提交事务。

需要注意的是,我们在实现向数据库中添加数据的时候,需要将其标注为事务, @Transactional(fallback = Exception.class) 指定发生什么异常就回滚。

@RocketMQTransactionListener(txProducerGroup = "tx-add-bonus-group")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class AddBonusTransactionListener implements RocketMQLocalTransactionListener {
    private final ShareService shareService;
    private final RocketmqTransactionLogMapper rocketmqTransactionLogMapper;

    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        MessageHeaders headers = msg.getHeaders();

        String transactionId = (String) headers.get(RocketMQHeaders.TRANSACTION_ID);
        Integer shareId = Integer.valueOf((String) headers.get("share_id"));

        String dtoString = (String) headers.get("dto");
        ShareAuditDTO auditDTO = JSON.parseObject(dtoString, ShareAuditDTO.class);

        try {
            this.shareService.auditByIdWithRocketMqLog(shareId, auditDTO, transactionId);
            return RocketMQLocalTransactionState.COMMIT;
        } catch (Exception e) {
            return RocketMQLocalTransactionState.ROLLBACK;
        }
    }

    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        MessageHeaders headers = msg.getHeaders();
        String transactionId = (String) headers.get(RocketMQHeaders.TRANSACTION_ID);

        // select * from xxx where transaction_id = xxx
        RocketmqTransactionLog transactionLog = this.rocketmqTransactionLogMapper.selectOne(
            RocketmqTransactionLog.builder()
                .transactionId(transactionId)
                .build()
        );
        if (transactionLog != null) {
            return RocketMQLocalTransactionState.COMMIT;
        }
        return RocketMQLocalTransactionState.ROLLBACK;
    }
}

SpringCloud Stream

SpringCloud Stream为我们提供了更加简便以及高效操作MQ的渠道,目前SpringCloud支持Kafka、RocketMQ、RabbitMQ,是一个便捷集成MQ的框架。Stream只是为我们提供了一个方便使用MQ的方法,MQ自身的依赖还是要引入的。

生产者

  1. 使用spring-cloud-starter-stream-rocketmq引入对应的依赖,如果是rabbitMQ,引入的就是amqp。
  2. 在启动类上加上@EnableBinding(Source.class)
  3. 添加配置信息
spring:
  cloud:
    stream:
      rocketmq:
        binder:
        #MQ服务器所在地址,这个和racketMQ配置的是同一个地址
          name-server: 127.0.0.1:9876
      bindings:
        output:
        #指定topic
          destination: stream-test-topic
  1. 注入Source类(类型和主类加的注解一样),这里的OutPut表示自己向外发送,而InPut则相反。
@Autowired
private Source source;

@GetMapping()
public STring testStream(){
  //这里需要一个Message类型的参数
  //可以使用MessageBuilder.withPayLoad( 实体类 ).build() 来构建一个Message类
  this.source.output().send(Message<> T)
}

消费者

  1. 使用spring-cloud-starter-stream-rocketmq引入对应的依赖,如果是rabbitMQ,引入的就是amqp。
  2. 在启动类上加上@EnableBinding(Sink.class)
  3. 添加配置信息
spring:
  cloud:
    stream:
      rocketmq:
        binder:
        #MQ服务器所在地址
          name-server: 127.0.0.1:9876
      bindings:
        itput:
        #指定topic
          destination: stream-test-topic
          # 一定要设置消费者组  如果其他MQ可以不设置
          group: binder-group
  1. 注入Source类(类型和主类加的注解一样),这里的OutPut表示自己向外发送,而InPut则相反。

@StreamListener(Sink.class)
public String receive(String messageBody){
  //处理消息即可
}

自定义Stream接口实现消费消息

  1. 自定义Stream接口MySink
public interface MySource{
  String MY_INPUT = "my-input";
  @IPut(MY_INPUT)
  SubscribableChannel input();
  1. 在启动类上注册上文自定义的接口类型 @EnableBinding({Sink.class , MySink.class})
  2. 在配置文件中加入自定义配置
spring:
  cloud:
    stream:
      rocketmq:
        binder:
        #MQ服务器所在地址,这个和racketMQ配置的是同一个地址
        # 配置了这个就可以不用单独配置rocketMQ了
          name-server: 127.0.0.1:9876
      bindings:
        output:
        #指定topic
          destination: stream-test-topic
        my-outout: #这个一定要和自己定义的名字相同
          destination: stream-my-topic
  1. 注入自己定义的接口使用即可。

PS:这里要注意,接口可能会被MyBatis的扫描路径扫描到。

自定义Stream接口实现生产消息

  1. 自定义Stream接口MySource
public interface MySource{
  String MY_OUTPUT = "my-output";
  @OutPut(MY_OUTPUT)
  MessageChannel output();
  1. 在启动类上加上上文自定义的接口类型 @EnableBinding({Sink.class , MySource.class})
  2. 在配置文件中加入自定义配置
spring:
  cloud:
    stream:
      rocketmq:
        binder:
        #MQ服务器所在地址
          name-server: 127.0.0.1:9876
      bindings:
        itput:
        #指定topic
          destination: stream-test-topic
          # 一定要设置消费者组  如果其他MQ可以不设置
          group: binder-group
        my-input:
          destination: stream-my-topic
          group: my-group
  1. 注入自己定义的接口使用即可。

消息过滤

Spring Cloud Stream实现消息过滤消费

SpringCloud Stream 监控

在这里插入图片描述

Stream 错误处理

Spring Cloud Stream错误处理详解

Spring Cloud Stream + RocketMQ实现分布式事务

重构生产者

stream:
      rocketmq:
        binder:
          name-server: 127.0.0.1:9876
          #这里是因为使用Stream的send方法,所以要将channel名配置在这里,并且开启事务
        bindings:
          output:
            producer:
              transactional: true
              group: tx-add-bonus-group
      bindings:
        output:
          # 用来指定topic
          destination: add-bonus

这里就是将RocketMQTemplate换成Stream的send方法,其他的代码几乎不用重构。因为send方法的参数太少,所以要用header来进行参数传递,并且header会将参数自动转换成String,配置文件中的名称一定要和二次监听中的名字一样。

重构消费者

spring:
  cloud:
    stream:
      rocketmq:
        binder:
        #MQ服务器所在地址
          name-server: 127.0.0.1:9876
      bindings:
        input:
        #指定topic
          destination: add-bonus
          # 一定要设置消费者组  如果其他MQ可以不设置
          group: binder-group

Input对象和OutPut接口对象声明后,如果要使用,就使用@Autowired进行注入。凡是设计到本地数据库的操作,最好使用事务另外封装一个方法,在MQ的方法调用即可。

SpringCloud Stream 知识盘点

Spring Cloud Stream知识点盘点

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值