简介
Spring Event 主要是为了解耦代码使用, 但是会有这样一种情况, 订单创建成功打印小票和添加库存,如果订单创建失败了,事件已经发送成功了,像这种情况肯定不能容忍的,所以给事件添加上事务
🧲[官方文档] Additional Capabilities of the ApplicationContext
🧲[相关文章] Spring Event / 事件的使用 一: ApplicationEvent
方法 / 步骤
- 添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
一: 定义事件实体
- 📄 Order.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
private Long orderId;
private String name;
}
- 📄OrderPayEvent.java
/**
* Description:
*
* @author: YangGC
*/
public class OrderPayEvent extends ApplicationEvent {
/**
* 当前订单对象
* @param source
*/
private Order order;
public OrderPayEvent(Object source) {
super(source);
this.order = (Order) source;
}
public Order getOrder() {
return order;
}
}
二: 定义监听器
定义监听者的方式,Spring提供了两种,一种是接口方式,一种是注解方式。
2.1: 接口方式
这里定义了两个监听者,实现泛型接口ApplicationListener类型为我们刚定义的OrderPayedEvent这里加上Order注解,是因为我们有多个监听者,有此业务场景中可能会有顺序的要求!
- 📄OrderPayedPrinterListener.java
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener;
/**
* Description:
*
* @author: YangGC
*/
@Component
public class OrderPayedListener {
@TransactionalEventListener(fallbackExecution = true)
public void handler(OrderPayEvent orderPayEvent){
//todo 添加业务处理
System.out.println(orderPayEvent.toString());
System.out.printf("【线程 - %s 】订单成功成功:第一步,打印小票%n", Thread.currentThread().getName());
System.out.printf("【线程 - %s 】订单成功成功:第二步,发送通知商品中心添加库存%n", Thread.currentThread().getName());
}
}
三: 发送事件
- 📄 ShoppingMallConsumerApplication.java
@SpringBootApplication
public class ShoppingMallConsumerApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(ShoppingMallConsumerApplication.class);
}
//这里注入 应用上下文,可以注入 applicationEventPublisher
@Resource
ApplicationContext context;
// @Resource
// ApplicationEventPublisher applicationEventPublisher;
@Override
public void run(String... args) throws Exception {
context.publishEvent(new OrderPayEvent(new Order(100L,"酸菜鱼")));
}
}
- 打印结果
com.iooiee.event.OrderPayEvent[source=Order(orderId=100, orderName=酸菜鱼)]
【线程 - main 】订单成功成功:第一步,打印小票
【线程 - main 】订单成功成功:第二步,发送通知商品中心添加库存
异步处理
ApplicationEvent对异步支持是怎么样的呢?
只要在启动类上加上@EnableAsync,在监听器类注解加上@Async
- 📄 ShoppingMallConsumerApplication.java
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener;
/**
* Description:
*
* @author: YangGC
*/
@Component
public class OrderPayedListener {
@Async
@TransactionalEventListener(fallbackExecution = true)
public void handler(OrderPayEvent orderPayEvent){
//todo 添加业务处理
System.out.println(orderPayEvent.toString());
System.out.printf("【线程 - %s 】订单成功成功:第一步,打印小票%n", Thread.currentThread().getName());
System.out.printf("【线程 - %s 】订单成功成功:第二步,发送通知商品中心添加库存%n", Thread.currentThread().getName());
}
}
- 打印结果
com.iooiee.event.OrderPayEvent[source=Order(orderId=100, orderName=酸菜鱼)]
【线程 - task-1 】订单成功成功:第一步,打印小票
【线程 - task-1 】订单成功成功:第二步,发送通知商品中心添加库存
事务处理
记得在事务处理中,异步操作在事务提交之后进行事件发送,不然可能查询不到同事务里面处理的数据
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit(){
context.publishEvent(new OrderPayEvent(new Order(100L,"酸菜鱼")));
}
});