In the actual business development process, the business logic may be very complex, with core business + N sub-businesses . If all of them are done together, the code may be very long, the coupling degree will continue to rise, and maintenance will be troublesome and even a headache. There are also some business scenarios that do not need to be completed synchronously in one request, such as email sending, SMS sending, etc.

MQ can indeed solve this problem, but MQ is heavy, and it is not necessary to increase the complexity of the architecture.

For these problems, let's take a look at Spring Event.

Synchronous use of Spring Event

Spring Event (Application Event) is actually an observer design pattern . After a bean completes a task, it wants to notify other beans or a bean wants to observe the behavior of another bean.

Spring Event is really easy to use for decoupling business!

1. Custom events

Define an event, and a class that inherits ApplicationEvent becomes an event class

 /**
 * @author Strive
 * @date 2022/4/22 18:00
 * @description
 */
@Data
@ToString
public class OrderProductEvent extends ApplicationEvent {

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

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

2. Define the listener

Monitor and process events, implement the ApplicationListener interface or use the @EventListener annotation

 /**
 * 实现 ApplicationListener 接口,并指定监听的事件类型
 *
 * @author Strive
 * @date 2022/4/24 09:09
 * @description
 */
@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));
  }
}

3. Define the publisher

Post an event, via ApplicationEventPublisher post an event

 /**
 * @author Strive
 * @date 2022/4/24 09:25
 * @description
 */
@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 "购买成功";
  }
}

4. Single test execution

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

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

The execution result is as follows:

 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)毫秒

Asynchronous use of Spring Event

Some business scenarios do not need to be completed synchronously in one request, such as email sending, SMS sending, etc.

1. Custom events

 @Data
@AllArgsConstructor
public class MsgEvent {

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

2. Define the listener

Recommended use @EventListener annotation

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

3. Define the publisher

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

4. Single Test Execution (Synchronous)

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

The execution result is as follows:

 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)毫秒

5. Enable asynchronous

Added startup class @EnableAsync note

 @EnableAsync
@SpringBootApplication
public class MingYueSpringbootEventApplication {

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

Listener class needs to enable asynchronous method addition @Async note

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

6. Single test execution (asynchronous)

The thread that sends the SMS shows task-1 , and after the main thread ends (total time: (2017) milliseconds) the console stops printing

 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   : 开发发送邮件

One last word (don't be a prostitute, please pay attention)

Every article of Chen Mou is carefully output. He has written 3 columns and organized them into PDF . The way to get it is as follows:

  1. "Spring Cloud Advanced" PDF: Follow the official account: [ Java Backend Interviewer ] Reply to the keyword Spring Cloud Advanced Get it!
  2. "Spring Boot Advanced" PDF: Follow the official account: [ Java Backend Interviewer ] Reply to the keyword Spring Boot Advanced Get!
  3. "Mybatis Advanced" PDF: Follow the official account: [ Java back-end interviewer ] Reply to the keyword Mybatis Advanced Get it!

If this article is helpful or inspiring to you, please help to like , watch , forward , and favorite . Your support is the biggest motivation for me to persevere!

This article is published by mdnice Multiplatform


码猿技术专栏
486 声望108 粉丝