Spring Event

        实际业务开发中,业务逻辑可能十分复杂,通常是核心业务逻辑+N个子业务。如果到写在一起,代码将会非常长,耦合度不断攀升,后期的维护也将会非常麻烦。还有一些业务场景不需要在一次请求中同步完成,如邮件发送,短信发送等。

在同一个项目应用进程中,当然可以用MQ来解决此问题,本着不提升架构复杂的原则,我们可以使用spring Event来轻松解决。

Spring Event本质就是一个观察者设计模式。一个bean处理完任务后通知其他bean,或者说一个bean想观察监听另一个bean的行为。

同步事件

自定义事件

import lombok.Data;
import lombok.ToString;
import org.springframework.context.ApplicationEvent;


@Data
@ToString
public class OrderProductEvent extends ApplicationEvent {

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

  public OrderProductEvent(Object source, String orderId) {
    super(source);
    this.orderId = orderId;
  }
}

定义监听事件

监听并处理事件,实现 ApplicationListener 接口或者使用 @EventListener 注解:

import com.csp.mingyue.event.events.OrderProductEvent;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;


@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));
  }
}

 定义发布者

import com.csp.mingyue.event.events.OrderProductEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

@Slf4j
@Service
@RequiredArgsConstructor
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.短信通知(异步处理)

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

测试

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest
public class OrderServiceTest {
  @Autowired 
  private OrderService orderService;

  @Test
  public void buyOrderTest() {
    orderService.buyOrder("732171109");
  }
}

执行结果

2022-04-24 10:13:17.535  INFO 44272 --- [           main] c.c.m.e.listener.OrderProductListener    : 732171109:校验订单商品价格耗时:(2008)毫秒
2022-04-24 10:13:17.536  INFO 44272 --- [           main] c.c.mingyue.event.service.OrderService   : 任务全部完成,总耗时:(2009)毫秒

异步事件

自定义事件

import lombok.AllArgsConstructor;
import lombok.Data;


@Data
@AllArgsConstructor
public class MsgEvent {

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

定义监听器

推荐使用@EventListener

import com.csp.mingyue.event.events.MsgEvent;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;


@Slf4j
@Component
public class MsgListener {

  @SneakyThrows
  @EventListener(MsgEvent.class)
  public void sendMsg(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));
  }
}

定义发布者

/**
  * 下单
  *
  * @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 "购买成功";
}

测试

@Test
public void buyOrderTest() {
    orderService.buyOrder("732171109");
}

执行结果

2022-04-24 10:24:13.905  INFO 54848 --- [           main] c.c.m.e.listener.OrderProductListener    : 732171109:校验订单商品价格耗时:(2004)毫秒
2022-04-24 10:24:13.906  INFO 54848 --- [           main] c.c.mingyue.event.listener.MsgListener   : 开发发送短信
2022-04-24 10:24:13.907  INFO 54848 --- [           main] c.c.mingyue.event.listener.MsgListener   : 开发发送邮件
2022-04-24 10:24:17.908  INFO 54848 --- [           main] c.c.mingyue.event.listener.MsgListener   : 732171109:发送短信、邮件耗时:(4002)毫秒
2022-04-24 10:24:17.908  INFO 54848 --- [           main] c.c.mingyue.event.service.OrderService   : 任务全部完成,总耗时:(6008)毫秒

开启异步

启动类增加 @EnableAsync 注解:

@EnableAsync
@SpringBootApplication
public class MingYueSpringbootEventApplication {

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

Listener 类需要开启异步的方法增加 @Async 注解:

@Async
@SneakyThrows
@EventListener(MsgEvent.class)
public void sendMsg(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));
}

测试(异步)

发送短信的线程显示 task-1,主线程结束后(总耗时:(2017)毫秒)控制台停止打印了:

2022-04-24 10:30:59.002  INFO 59448 --- [           main] c.c.m.e.listener.OrderProductListener    : 732171109:校验订单商品价格耗时:(2009)毫秒
2022-04-24 10:30:59.009  INFO 59448 --- [           main] c.c.mingyue.event.service.OrderService   : 任务全部完成,总耗时:(2017)毫秒
2022-04-24 10:30:59.028  INFO 59448 --- [         task-1] c.c.mingyue.event.listener.MsgListener   : 开发发送短信
2022-04-24 10:30:59.028  INFO 59448 --- [         task-1] c.c.mingyue.event.listener.MsgListener   : 开发发送邮件

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值