SpringBoot Event 事件

266 阅读2分钟

前言

有这么个场景,用户下订单,下单成功需要短信通知用户。

当然第一想到的是通过 MQ 消息队列来实现,但是 MQ 比较重,需要引入新的中间件。

可以采用 SpringBoot 自带的一种消息通知实现方式

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

两种实现方式

继承 ApplicationEvent 类

定义一个 Event,继承 ApplicationEvent

@Getter
public class DemoEvent extends ApplicationEvent {

    private String orderId;

    /**
     * Create a new {@code ApplicationEvent}.
     *
     * @param source the object on which the event initially occurred or with
     *               which the event is associated (never {@code null})
     */
    public DemoEvent(Object source, String orderId) {
        super(source);
        this.orderId = orderId;
    }
}

定义一个 listener,实现 ApplicationListener

@Component
@Slf4j
public class DemoListener implements ApplicationListener<DemoEvent> {

    // @Resource
    // private MsgService msgService;

    @SneakyThrows
    @Override
    public void onApplicationEvent(DemoEvent event) {
        String orderId = event.getOrderId();
        long start = System.currentTimeMillis();
        TimeUnit.SECONDS.sleep(2);
        long end = System.currentTimeMillis();
        // String send = msgService.send("订单" + orderId + "下单成功");
        // log.info("消息发送:{}", send);
        log.info("订单{}耗时:{}ms", orderId, (end - start));
    }
}

事件发布

@Slf4j
@Service
public class DemoService {

    @Autowired
    private ApplicationContext context;

    public String buy(String orderId) {
        long start = System.currentTimeMillis();
        context.publishEvent(new DemoEvent(this, orderId));
        long end = System.currentTimeMillis();
        log.info("任务完成{}耗时:{}ms", orderId, (end - start));
        return "购买成功";
    }

}

注解方式

定义一个 Event

@Data
@AllArgsConstructor
public class MsgEvent {

    private String msg;

}

定义监听器

使用 @EventListener 注解

@Component
@Slf4j
public class MsgListener {

    // @Async
    @SneakyThrows
    @EventListener(MsgEvent.class)
    public void sendMsg(MsgEvent event) {
        String orderId = event.getMsg();
        long start = System.currentTimeMillis();
        TimeUnit.SECONDS.sleep(2);
        long end = System.currentTimeMillis();
        log.info("订单{}耗时:{}ms", orderId, (end - start));
    }

}

事件发布

@Slf4j
@Service
public class MsgService {

    @Autowired
    private ApplicationContext context;

    public String send(String msg) {
        long start = System.currentTimeMillis();
        context.publishEvent(new MsgEvent(msg));
        long end = System.currentTimeMillis();
        log.info("任务完成{}耗时:{}ms", msg, (end - start));
        return "发送成功";
    }

}

可以采用异步方式,只需要在 listener 方法上添加 @Async 注解

@Component
@Slf4j
public class MsgListener {

    @Async
    @SneakyThrows
    @EventListener(MsgEvent.class)
    public void sendMsg(MsgEvent event) {
        String orderId = event.getMsg();
        long start = System.currentTimeMillis();
        TimeUnit.SECONDS.sleep(2);
        long end = System.currentTimeMillis();
        log.info("订单{}耗时:{}ms", orderId, (end - start));
    }

}

同时,启动类开启异步注解

@SpringBootApplication
@EnableAsync
public class EventDemoApplication {

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

}