java ---Spring事件监听
目录
实现方式:
1.接口方式
2.注解方式
监听事件后异步执行
顺序获取事件
事件发布是 Spring 框架中最容易被忽视的功能之一,但实际上它是一个很有用的功能。使用事件机制可以将同一个应用系统内互相耦合的代码进行解耦,并且可以将事件与 Spring 事务结合起来,实现我们工作中的一些业务需求。
今天聊聊spring中的事件,帮助需要的伙伴快速上手这一模块。
事件简单理解包含三个要素:
- 事件源:谁触发了这个事件?
- 事件:发生了什么?
- 事件监听器:事件发生后要做什么?
业务场景:支付之后给用户发送信息,提示支付成功
实现方式:
1.接口方式
事件类:
自定义传递的事件属性
@Getter
@Setter
@ToString
public class EmailEvent extends ApplicationEvent {/* 事件id*/private Integer id;/* 事件数据*/private Object data;/* 事件描述*/private String message;private final String type = "email";public EmailEvent(Object source) {super(source);}}
监听器类:
这里要实现AppliListener这个接口
@Slf4j
@Component
public class Listener implements ApplicationListener<EmailEvent> {@Overridepublic void onApplicationEvent(EmailEvent event) {log.info("监听事件成功! ");log.info("发送信息:用户【{}】,您已成功支付! " , event.getData());}}
测试用例:
要注入ApplicationEventPublisher,用来发布事件
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {@Autowiredprivate ApplicationEventPublisher publisher;@PostMapping("/1")public void test(){//发送事件开始 log.info("事件1发送 " );EmailEvent emailEvent = new EmailEvent(this);emailEvent.setId(1);emailEvent.setMessage("支付成功!");emailEvent.setData("simon.wayne");publisher.publishEvent(emailEvent);}
}
输出结果:
事件1发送
监听事件成功!
发送信息:用户【simon.wayne】,您已成功支付!
2.注解方式
事件类:
自定义传递的事件属性
@Getter
@Setter
@ToString
public class EmailEvent extends ApplicationEvent {/* 事件id*/private Integer id;/* 事件数据*/private Object data;/* 事件描述*/private String message;private final String type = "email";public EmailEvent(Object source) {super(source);}}
测试用例:
要注入ApplicationEventPublisher,用来发布事件,并通过@EventListener注解在方法上监听事件
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {@Autowiredprivate ApplicationEventPublisher publisher;@PostMapping("/1")public void test(){//发送事件开始 log.info("事件1发送 " );EmailEvent emailEvent = new EmailEvent(this);emailEvent.setId(1);emailEvent.setMessage("支付成功!");emailEvent.setData("simon.wayne");publisher.publishEvent(emailEvent);}@EventListenerpublic void accept(EmailEvent event){log.info("接收事件1 ,事件描述:{},事件数据:{} " , event.getMessage(),event.getData());log.info("发送信息:用户【{}】,您已成功支付! " , event.getData());}}
输出结果:
事件1发送
接收事件1事件描述:支付成功!,事件数据: simon.wayne
发送信息:用户【simon.wayne】,您已成功支付!
监听事件后异步执行
1.证明事件的同步性,方法发布事件,在监听器拿到事件后,执行完成才能方法才能继续执行
这里让监听器拿到事件后线程睡眠五秒钟
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {@Autowiredprivate ApplicationEventPublisher publisher;@PostMapping("/1")public void test(){//发送事件开始 2023年3月27日09:57:42log.info("事件1发送 " );EmailEvent emailEvent = new EmailEvent(this);emailEvent.setId(1);emailEvent.setMessage("支付成功!");emailEvent.setData("simon.wayne");publisher.publishEvent(emailEvent);log.info("方法结束!");}@EventListenerpublic void accept(EmailEvent event) throws InterruptedException {log.info("接收事件1 ,事件描述:{},事件数据:{} " , event.getMessage(),event.getData());log.info("发送信息:用户【{}】,您已成功支付! " , event.getData());Thread.sleep(5000);}
}
输出结果:
事件1发送
接收事件1 ,事件描述:支付成功!,事件数据:simon.wayne
发送信息:用户【simon.wayne】,您已成功支付!
方法结束!
最后一行结果方法结束延迟了五秒才出现,充分证明事件是以同步的方式执行的,接下来就介绍异步执行的方法。
2.事件异步执行
方法很简单:在启动类上加一个@EnableAsync注解,启用异步功能,然后监听器方法上添加 @Async
注解即可。
测试示例
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {@Autowiredprivate ApplicationEventPublisher publisher;@PostMapping("/1")public void test(){//发送事件开始 2023年3月27日09:57:42log.info("事件1发送 " );EmailEvent emailEvent = new EmailEvent(this);emailEvent.setId(1);emailEvent.setMessage("支付成功!");emailEvent.setData("simon.wayne");publisher.publishEvent(emailEvent);log.info("方法结束!");}@Async@EventListenerpublic void accept(EmailEvent event) throws InterruptedException {Thread.sleep(5000);log.info("接收事件1 ,事件描述:{},事件数据:{} " , event.getMessage(),event.getData());log.info("发送信息:用户【{}】,您已成功支付! " , event.getData());}
此时的输出结果:
事件1发送
方法结束!
接收事件1 ,事件描述:支付成功!,事件数据:simon.wayne
发送信息:用户【simon.wayne】,您已成功支付!
可以发现此时已是异步执行
顺序获取事件
在监听方法上加上一个@order注解,order的值越小,优先级越高
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {@Autowiredprivate ApplicationEventPublisher publisher;@PostMapping("/1")public void test(){//发送事件开始 2023年3月27日09:57:42log.info("事件1发送 " );EmailEvent emailEvent = new EmailEvent(this);emailEvent.setId(1);emailEvent.setMessage("支付成功!");emailEvent.setData("simon.wayne");publisher.publishEvent(emailEvent);log.info("方法结束!");}@Order(1)@EventListenerpublic void sendMessage(EmailEvent event) throws InterruptedException {log.info("接收事件1 ,事件描述:{},事件数据:{} " , event.getMessage(),event.getData());log.info("发送信息:用户【{}】,您已成功支付! " , event.getData());}@Order(2)@EventListenerpublic void deliverGoods(EmailEvent event) throws InterruptedException {log.info("接收事件1 ,事件描述:{},事件数据:{} " , event.getMessage(),event.getData());log.info("发货:用户【{}】,您的商品已发货! " , event.getData());}
}
输出结果:
事件1发送
接收事件1 ,事件描述:支付成功!,事件数据:simon.wayne
发送信息:用户【simon.wayne】,您已成功支付!
接收事件1 ,事件描述:支付成功!,事件数据:simon.wayne
发货:用户【simon.wayne】,您的商品已发货!
方法结束!
可以看出 是先发送信息后发货