SpringCloud Bus 实现事件的发布订阅

227 阅读2分钟

1. 前置准备

Rabbitmq环境 创建三个模块:A(用来发布),B(用来消费),C(作为公共模块被AB引入)

2.创建项目

A,B模块同时引入依赖

<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

bootstrap.yml中配置rabbitmq链接

spring:
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest

bus相关配置

spring:
  cloud:
    bus:
      enabled: true
      id: A-server  #id的配置可以跟application.name一致

3.公共模块C的代码

创建事件对象,事件需要继承RemoteApplicationEvent类:

import org.springframework.cloud.bus.event.RemoteApplicationEvent;

public class CustomEvent extends RemoteApplicationEvent {
    private String uid;  // 业务uid
    private String operationType; // 业务类型

    // 必须有无参构造(用于序列化)
    public CustomEvent() {
        super();
    }

    // 全参构造
    public CustomEvent(Object source, String originService, String destination, String uid, String operationType) {
        super(source, originService, destination);
        this.uid = uid;
        this.operationType = operationType;
    }



    // Getter/Setter
    public String getUid() { return uid; }
    public void setUid(String uid) { this.uid = uid; }
    public String getOperationType() { return operationType; }
    public void setOperationType(String operationType) { this.operationType = operationType; }

}

重点在originService和destination这两个参数上,originService就是上面配置的bus.id,destination是目标服务的application.name

4.服务A事件发布代码

@Slf4j
@Component
public class EventSender {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Autowired
    private BusProperties busProperties;

    /**
     * 发布事件
     *
     * @param originService 发送方微服务名称,如:A-service
     * @param destination   发送到那个微服务,如:B-service
     * @param uid           业务uid
     * @param operationType 操作类型
     */
    public void sendEvent(String originService, String destination, String uid, String operationType) {
        CustomEvent event = new CustomEvent(
                this,
                originService, //如果没有配置bus.id,这也可以使用busProperties.getId()
                destination,
                uid,
                operationType
        );
        System.out.println("Bus start publishing event");
        eventPublisher.publishEvent(event);
        System.out.println("Bus publish event success");
    }
}

@SpringBootApplication
@RemoteApplicationEventScan(basePackages = "com.xx.c.common.event") // 注意这里的包是在C中定义事件的那个包路径
public class AApplication {

    public static void main(String[] args) {
        SpringApplication.run(AApplication.class, args);
    }
}
@RestController
@RequestMapping("/bus/publish")
public class TestController {
    @Autowired
    private EventSender eventSend;

    @GetMapping("/test")
    public Boolean test(){
        return eventSend.sendEvent("A-service","B-service","111","xxx");
    }
}

5.服务B事件订阅代码

@Slf4j
@Component
public class EventListener  {

    @EventListener(condition = "#event.operationType == 'xxx'")
    public void handleCustomEvent(CustomEvent event) throws Exception {
        try {
            log.info("\n=== 收到跨服务事件 ===");
            log.info("来源服务: " + event.getOriginService());
            log.info("消息容内: " + event.getUid());
            log.info("操作类型: " + event.getOperationType());
            // 下面处理你自己的业务
           
            log.info("==========跨服务事件处理完成==========\n");
        }catch (Exception e){
            log.error("跨服务事件处理失败",e);
           // 可以记录下错误日志
        }
    }

}
@SpringBootApplication
@RemoteApplicationEventScan(basePackages = "com.xx.c.common.event") // 注意这里的包是在C中定义事件的那个包路径
public class BApplication {

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

6.测试

这里就不做展示了