Spring Boot Event 观察者模式,轻松实现业务解耦!

开发 架构
Spring Event(Application Event)其实就是一个观察者设计模式,一个 Bean 处理完成任务后希望通知其它 Bean 或者说一个 Bean 想观察监听另一个Bean 的行为。

实际业务开发过程中,业务逻辑可能非常复杂,核心业务 + N个子业务。如果都放到一块儿去做,代码可能会很长,耦合度不断攀升,维护起来也麻烦,甚至头疼。还有一些业务场景不需要在一次请求中同步完成,比如邮件发送、短信发送等。

MQ 确实可以解决这个问题,但 MQ 重啊,非必要不提升架构复杂度。

针对这些问题,我们了解一下 Spring Event。

Spring Event 同步使用

Spring Event(Application Event)其实就是一个观察者设计模式,一个 Bean 处理完成任务后希望通知其它 Bean 或者说一个 Bean 想观察监听另一个Bean 的行为。

Spring Event 用来解耦业务真的贼好用!

1. 自定义事件

定义事件,继承 ApplicationEvent 的类成为一个事件类;

/**
* @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. 定义监听器

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

/**
* 实现 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. 定义发布者

发布事件,通过 ApplicationEventPublisher 发布事件;

推荐个人知识总结网站:www.java-family.cn。

/**
* @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.单测执行

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

Spring Event 异步使用

有些业务场景不需要在一次请求中同步完成,比如邮件发送、短信发送等。

1. 自定义事件

@Data
@AllArgsConstructor
public class MsgEvent {

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

2. 定义监听器

推荐使用 @EventListener 注解;

@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. 定义发布者

/**
* 下单
* @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. 单测执行(同步)

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

5.开启异步

启动类增加 @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));
}

6.单测执行(异步)

发送短信的线程显示 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

责任编辑:武晓燕 来源: 码猿技术专栏
相关推荐

2021-04-14 14:40:37

forSpringJava

2021-03-29 07:14:28

Spring观察者模式

2020-10-26 08:45:39

观察者模式

2021-07-08 11:28:43

观察者模式设计

2013-11-26 17:09:57

Android设计模式

2021-09-06 10:04:47

观察者模式应用

2022-01-29 22:12:35

前端模式观察者

2012-08-27 10:52:20

.NET架构观察者模式

2015-11-25 11:10:45

Javascript设计观察

2009-03-30 09:39:04

观察者思想换位设计模式

2022-11-15 07:35:50

Spring事件观察者模式

2022-09-02 08:23:12

软件开发解耦架构

2021-06-03 12:26:28

观察者模式面试阿里P6

2021-01-25 05:38:04

设计原理VueSubject

2021-09-29 19:45:24

观察者模式Observable

2021-03-30 15:30:44

鸿蒙HarmonyOS应用开发

2022-05-09 10:50:13

观察者模式设计模式

2021-06-07 20:03:04

监听器模式观察者

2021-11-08 11:32:01

观察

2020-10-16 18:41:43

command设计模式代码
点赞
收藏

51CTO技术栈公众号