目录
实现方式:
1.接口方式
2.注解方式
监听事件后异步执行
顺序获取事件
事件发布是 Spring 框架中最容易被忽视的功能之一,但实际上它是一个很有用的功能。使用事件机制可以将同一个应用系统内互相耦合的代码进行解耦,并且可以将事件与 Spring 事务结合起来,实现我们工作中的一些业务需求。
今天聊聊spring中的事件,帮助需要的伙伴快速上手这一模块。
事件简单理解包含三个要素:
业务场景:支付之后给用户发送信息,提示支付成功
事件类:
自定义传递的事件属性
@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 {
@Override
public void onApplicationEvent(EmailEvent event) {
log.info("监听事件成功! ");
log.info("发送信息:用户【{}】,您已成功支付! " , event.getData());
}
}
测试用例:
要注入ApplicationEventPublisher,用来发布事件
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private 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】,您已成功支付!
事件类:
自定义传递的事件属性
@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 {
@Autowired
private 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);
}
@EventListener
public 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 {
@Autowired
private ApplicationEventPublisher publisher;
@PostMapping("/1")
public void test(){
//发送事件开始 2023年3月27日09:57:42
log.info("事件1发送 " );
EmailEvent emailEvent = new EmailEvent(this);
emailEvent.setId(1);
emailEvent.setMessage("支付成功!");
emailEvent.setData("simon.wayne");
publisher.publishEvent(emailEvent);
log.info("方法结束!");
}
@EventListener
public 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 {
@Autowired
private ApplicationEventPublisher publisher;
@PostMapping("/1")
public void test(){
//发送事件开始 2023年3月27日09:57:42
log.info("事件1发送 " );
EmailEvent emailEvent = new EmailEvent(this);
emailEvent.setId(1);
emailEvent.setMessage("支付成功!");
emailEvent.setData("simon.wayne");
publisher.publishEvent(emailEvent);
log.info("方法结束!");
}
@Async
@EventListener
public 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 {
@Autowired
private ApplicationEventPublisher publisher;
@PostMapping("/1")
public void test(){
//发送事件开始 2023年3月27日09:57:42
log.info("事件1发送 " );
EmailEvent emailEvent = new EmailEvent(this);
emailEvent.setId(1);
emailEvent.setMessage("支付成功!");
emailEvent.setData("simon.wayne");
publisher.publishEvent(emailEvent);
log.info("方法结束!");
}
@Order(1)
@EventListener
public void sendMessage(EmailEvent event) throws InterruptedException {
log.info("接收事件1 ,事件描述:{},事件数据:{} " , event.getMessage(),event.getData());
log.info("发送信息:用户【{}】,您已成功支付! " , event.getData());
}
@Order(2)
@EventListener
public 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】,您的商品已发货!
方法结束!
可以看出 是先发送信息后发货