SpringBoot Event 观察者模式

前言

在我们实际业务开发过程中,往往会有核心业务+N多个子任务组成,都放在一块耦合度会不断升高,维护起来也会变得麻烦。还有一些业务场景不需要在一次请求中完成,例如发送短信等。
使用消息队列也可以解决这个问题,但是非必要的情况下不必提升架构复杂度。针对这些问题,我们了解一下 Spring Event。

使用步骤

一、Spring Event 同步使用

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

1.自定义事件

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

package com.example.demo.event;

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

/**
 * @description: 定义事件类
 * @author: hbc
 * @date: 2022-07-12 14:14
 */
@Data
public class OrderProductEvent extends ApplicationEvent {
    /**
     * 该事件携带的信息
     */
    private String orderId;

    public OrderProductEvent(Object source, String orderId) {
        super(source);
        this.orderId = orderId;
    }
}
2.定义监听器

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

package com.example.demo.event;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * @description: 定义监听器
 * @author: hbc
 * @date: 2022-07-12 14:18
 */
@Slf4j
@Component
public class OrderProductListener implements ApplicationListener<OrderProductEvent> {

    @SneakyThrows
    @Override
    public void onApplicationEvent(OrderProductEvent event) {
        String orderId = event.getOrderId();
        long start = System.currentTimeMillis();
        Thread.sleep(2000);
        long end = System.currentTimeMillis();
        log.info("收到监听校验商品价格,订单id为【{}】,用时:【{}】毫秒",orderId,end-start);
    }
}
3.定义发布者

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

package com.example.demo.event;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

/**
 * @description: 定义发布者
 * @author: hbc
 * @date: 2022-07-12 14:22
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderProductService {
    /**
     * 注入ApplicationContext用于发布事件
     */
    private final ApplicationContext applicationContext;

    /**
     * 下单操作
     * @param orderId 订单id
     * @return
     */
    public String bugOrder(String orderId){
        long start = System.currentTimeMillis();
        //1、其他业务操作
        log.info("开始下单");
        //2、检验订单价格(同步处理)
        applicationContext.publishEvent(new OrderProductEvent(this,orderId));
        //后续操作
        log.info("下单成功,返回结果");
        long end = System.currentTimeMillis();
        log.info("任务结束,全部耗时:【{}】",end-start);
        return "下单成功";
    }

}
4、执行
    @Autowired private OrderProductService orderProductService;
    @Test
    public void testEvent(){
        String result = orderProductService.bugOrder("12313131");
        System.err.println(result);
    }
5、结果

在这里插入图片描述

二、Spring Event 异步使用

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

1.开启异步

启动类增加 @EnableAsync 注解

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class DemoApplication {

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

}
2.自定义事件
package com.example.demo.event;

import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * @description: 自定义事件 发送短信
 * @author: hbc
 * @date: 2022-07-12 15:03
 */
@Data
@AllArgsConstructor
public class MsgEvent {

    /**
     * 该事件携带的信息:短信内容
     */
    private String message;
}
3.定义监听器

推荐使用 @EventListener 注解,开启异步的方法增加 @Async 注解

package com.example.demo.event;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * @description: 定义监听器
 * @author: hbc
 * @date: 2022-07-12 15:08
 */
@Slf4j
@Component
public class MsgListener {

    @Async
    @SneakyThrows
    @EventListener(MsgEvent.class)
    public void sendMsg(MsgEvent msgEvent){
        String message = msgEvent.getMessage();
        long start = System.currentTimeMillis();
        log.info("开始发送短信");
        Thread.sleep(2000);
        long end = System.currentTimeMillis();
        log.info("发送短信,短信内容为:【{}】,耗时:【{}】",message,end-start);
    }
}
4.定义发布者
package com.example.demo.event;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

/**
 * @description: 定义发布者
 * @author: hbc
 * @date: 2022-07-12 14:22
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderProductService {
    /**
     * 注入ApplicationContext用于发布事件
     */
    private final ApplicationContext applicationContext;

    /**
     * 下单操作
     * @param orderId 订单id
     * @return
     */
    public String bugOrder(String orderId){
        long start = System.currentTimeMillis();
        //1、其他业务操作
        log.info("开始下单");
        //2、检验订单价格(同步处理)
        applicationContext.publishEvent(new OrderProductEvent(this,orderId));
        //3、发送短信(异步处理)
        applicationContext.publishEvent(new MsgEvent("您好,正在执行下单操作"));
        //后续操作
        log.info("下单成功,返回结果");
        long end = System.currentTimeMillis();
        log.info("任务结束,全部耗时:【{}】",end-start);
        return "下单成功";
    }


}
5.执行
@Autowired private OrderProductService orderProductService;
@Test
public void testEvent(){
    String result = orderProductService.bugOrder("12313131");
    System.err.println(result);
}
6.结果

发送短信的线程显示 task-1,主线程结束后(总耗时:(2017)毫秒)控制台停止打印了
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值