springBoot自带事件

在某些应用场景,我们不想要整个业务流程中一部分耗时较长,且并不影响主流程的任务,同主流程一步一步的执行,这样很耽误对用户的响应。于是可以优化到同步执行或者异步去执行这些可以隔离的任务。比如邮件、短信的发送,交易通知带数据同步的问题。
常考虑到的是我们直接加入中间件,但是这样会增加系统的复杂性以及交易链路。所以遇到一般的支线任务,可考虑使用springBoot event.
通过demo了解这个过程,学习记录,欢迎指出不对或者建议.^^
首先得定义事件源,有以下几种的,根据场景任意选取

1-

public class MsgEvent {

  /** 该类型事件携带的信息 */
  public String orderId;
}

2-

public class OrderProductEvent extends ApplicationEvent {

  /** 该类型事件携带的信息 */
  private String orderId;

  /**
   * 在自定义事件的构造方法中除了第一个source参数,其他参数都可以去自定义,
   * 可以根据项目实际情况进行监听传参,这里就只定义个简单的String字符串的透传
   * @param source
   * @param orderId
   */
  public OrderProductEvent(Object source, String orderId) {
    super(source);
    this.orderId = orderId;
  }
}

3-

public class MyEventDemo extends ApplicationEvent {
    private static final Logger logger = LoggerFactory.getLogger(MyEventDemo.class);
    private MessageEntity messageEntity;

    /**
     * 在自定义事件的构造方法中除了第一个source参数,其他参数都可以去自定义,
     * 可以根据项目实际情况进行监听传参,这里就只定义个简单的String字符串的透传
     *
     * @param source
     * @param messageEntity
     */
    public MyEventDemo(Object source, MessageEntity messageEntity) {
        super(source);
        this.messageEntity = messageEntity;
    }

    public MessageEntity getMessageEntity() {
        return messageEntity;
    }

    public void setMessageEntity(MessageEntity messageEntity) {
        this.messageEntity = messageEntity;
    }
}

然后,得发布事件,一般在业务层处理,通过ApplicationContext,ApplicationEventPublisher的publishEvent(agrs)都可以.

public class OrderService {

  /** 注入ApplicationContext用来发布事件 */
  private final ApplicationContext applicationContext;

  /**
   * 下单
   *
   * @param orderId 订单ID
   */
  public String buyOrder(String orderId) {
    long start = System.currentTimeMillis();
    // 1.查询订单详情

    // 2.检验订单价格 (同步处理)
    applicationContext.publishEvent(new OrderProductEvent(this, orderId));

    // 3.短信通知(异步处理)
    applicationContext.publishEvent(new MsgEvent(orderId));

    long end = System.currentTimeMillis();
    log.info("任务全部完成,总耗时:({})毫秒", end - start);
    return "购买成功";
  }
}

最后便是事件的监听处理,可以通过@EventListener不配置参数监听方法内的对象事件。也可以通过@EventListener(MsgEvent.class)对象类这种方式监听,还可以通过监听对象中属性值来触发事件处理@EventListener(condition = “#event.orderId==‘123123’”)。对于异步事件来说,最好使用自定义线程池来处理,避免溢出。

@Slf4j
@Component
public class MsgListener {
  @Async
  @SneakyThrows
  @EventListener(MsgEvent.class)
  public void sendMsg(MsgEvent event) {
    String orderId = event.getOrderId();
    long start = System.currentTimeMillis();
    log.info("event开发发送短信");
    log.info("event开发发送邮件");
    Thread.sleep(4000);
    long end = System.currentTimeMillis();
    log.info("{}:event发送短信、邮件耗时:({})毫秒", orderId, (end - start));
  }

  /**
   * 按照具体条件值进行消费处理
   * @param event
   */
  @Async("taskExecutor")
  @SneakyThrows
  @EventListener(condition = "#event.orderId=='123123'")
  public void sendMsg123(MsgEvent event) {
    String orderId = event.getOrderId();
    long start = System.currentTimeMillis();
    log.info("开发发送短信");
    log.info("开发发送邮件");
    Thread.sleep(4000);
    long end = System.currentTimeMillis();
    log.info("{}:发送短信、邮件耗时:({})毫秒", orderId, (end - start));
  }

  @Async
  @SneakyThrows
  @EventListener(condition = "#event.orderId=='456456'")
  public void sendMsg456(MsgEvent event) {
    String orderId = event.getOrderId();
    long start = System.currentTimeMillis();
    log.info("开发发送短信");
    log.info("开发发送邮件");
    Thread.sleep(4000);
    long end = System.currentTimeMillis();
    log.info("{}:发送短信、邮件耗时:({})毫秒", orderId, (end - start));
  }
}

还可以通过实现ApplicationListenner接口重写接口的方式,监听事件

同步消费事件
@Slf4j
@Component
public class OrderProductListener implements ApplicationListener<OrderProductEvent> {

  /** 使用 onApplicationEvent 方法对消息进行接收处理 */
  @SneakyThrows
  @Override
  public void onApplicationEvent(OrderProductEvent event) {
    String orderId = event.getOrderId();
    long start = System.currentTimeMillis();
    Thread.sleep(2000);
    long end = System.currentTimeMillis();
    log.info("{}:校验订单商品价格耗时:({})毫秒", orderId, (end - start));
  }
}

测试测试

/**
     * 完整模板springboot的事件测试,@NotControllerResponseAdvice不对此返回做封装
     * @param orderId
     * @return
     */
    @GetMapping(value = "/fullVersionSpringBootEventTest")
    @NotControllerResponseAdvice
    public String fullVersionSpringBootEventTest(String orderId){
       return orderService.buyOrder(orderId);
    }

根据实际场景选取是否使用,自带的功能很多东西没有完善,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值