学习记录之【ApplicationEvent】

事件

事件,就是一系列的行为动作。例如:用户在系统页面的操作,在后台会记录下一个个行为日志,可以算做事件;用户支付了一个订单,也算做一个事件。

监听器

监听器,见名识意,指的是监听一个行为动作(事件),如果触发了就执行后续已经准备好的业务逻辑。这与消息队列中消费者监听器类似:监听到通道中有消息传来,就立马去消费。

实践

自定义事件类

//定义数据类型实体类,后面用于将该类型的数据传递到source
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EventInfo {
    private String eventName;
    private Integer eventType;
}

//定义自定义事件类
@Slf4j
public class MyEvent extends ApplicationEvent {
    public MyEvent(Object source) {
        super(source);
        log.info("MyEvent is create");
    }
}

定义监听类

监听器类有两种方式创建,第一种是实现ApplicationListener接口;另一个是使用@EventListener注解

接口方式

实现ApplicationListener接口,且泛型上界为ApplicationEvent

@Slf4j
@Component
public class MyEventListenerByInterface implements ApplicationListener<MyEvent> {
    @Override
    public void onApplicationEvent(MyEvent event) {
        log.info("eventListener-interface-start");
        EventInfo eventInfo = (EventInfo) event.getSource();
        log.info(JSONUtil.toJsonStr(eventInfo));
        log.info("eventListener-interface-end");
    }
}

注解方式

在方法上使用@EventListener注解,并指定事件类型,用于绑定监听器与事件类型

@Slf4j
@Component
public class MyEventListenerByAnnotation {
    @EventListener(classes = MyEvent.class)
    public void handleEvent(MyEvent event){
        log.info("eventListener-annotation-start");
        EventInfo eventInfo = (EventInfo) event.getSource();
        log.info(JSONUtil.toJsonStr(eventInfo));
        log.info("eventListener-annotation-end");
    }
}

发布事件

这里我们使用ApplicationContext接口作为发布事件的入口,因为该接口继承自ApplicationEventPublisher

@Slf4j
@RestController
public class MyEventController {
    @Resource
    private ApplicationContext applicationContext;

    @RequestMapping(value = "/event/push",method = RequestMethod.GET)
    public BaseResponse eventPush(){
        EventInfo eventInfo = new EventInfo("yyh", 25);
        log.info("controller-start");
        applicationContext.publishEvent(new MyEvent(eventInfo));
        log.info("controller-end");
        return BaseResponse.responseItem(eventInfo);
    }
}

执行结果

这里我们定义了两个监听器类,用于监听同一个MyEvent事件,所以每当调用一次/event/push接口,两个监听器都会触发,结果如下:

可以看到,触发一次事件,两个监听器执行时同步执行,且接口方式的监听器一定最先执行(注解实现时@Order无效),即使都加上了@Order注解。感兴趣的小伙伴可以实践一下。

异步执行

如果想要异步执行,节省接口调用时间,则可以在监听器的处理方法上加@Async注解(注意:启动类上也需要加@EnableAsync,用于允许异步执行),异步执行结果如下:

在这里插入图片描述

从截图可以看到,因为两个监听器分别加了@Async,所以单独为它们分配了两个线程执行任务,而且执行两个监听器打印的日志也是交错开来

总结

对于个人理解,ApplicationEvent事件模型配合@Async注解使用时,类似于消息队列的作用。就是不用直接引入消息队列中间件,实现代码解耦。业务场景如下:
1.例如数据同步,在用户在A系统下单时,需要将数据同步到系统B;
2.记录日志可以这么干,但是使用AOP切面更加稳妥方便。
个人疑问:如果不用ApplicationEvent,而只是单独抽出一个类使用@Async也能实现代码解耦,多这一步的目的在哪儿目前还没想明白。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值