[Java Framework] [Spring] Spring Event / 事件的使用 二: Transactional Event

简介: [Java Framework] [Spring] Spring Event / 事件的使用 二: Transactional Event

简介

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,"酸菜鱼")));
    }
});

参考资料 & 致谢

[1] Spring事件,ApplicationEvent在业务中的应用

目录
相关文章
|
8天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
28 2
|
2月前
|
监控 Java C#
Spring Event 的介绍
Spring Event 是 Spring 框架中的事件驱动机制,允许组件间进行同步或异步消息传递,无需直接依赖。它包括事件(Event)、事件发布者(Publisher)和事件监听器(Listener),通过 `ApplicationEventPublisher` 广播事件,实现松耦合通信,增强模块化和可维护性。Spring 还提供了多种内置事件,如 `ContextRefreshedEvent` 和 `ContextClosedEvent`,支持同步及异步处理,并具备良好的扩展性。
|
20天前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
28天前
|
前端开发 Java 数据库连接
Spring 框架:Java 开发者的春天
Spring 框架是一个功能强大的开源框架,主要用于简化 Java 企业级应用的开发,由被称为“Spring 之父”的 Rod Johnson 于 2002 年提出并创立,并由Pivotal团队维护。
43 1
Spring 框架:Java 开发者的春天
|
28天前
|
Java 数据库连接 开发者
Spring 框架:Java 开发者的春天
【10月更文挑战第27天】Spring 框架由 Rod Johnson 在 2002 年创建,旨在解决 Java 企业级开发中的复杂性问题。它通过控制反转(IOC)和面向切面的编程(AOP)等核心机制,提供了轻量级的容器和丰富的功能,支持 Web 开发、数据访问等领域,显著提高了开发效率和应用的可维护性。Spring 拥有强大的社区支持和丰富的生态系统,是 Java 开发不可或缺的工具。
|
28天前
|
JSON Java Maven
实现Java Spring Boot FCM推送教程
本指南介绍了如何在Spring Boot项目中集成Firebase云消息服务(FCM),包括创建项目、添加依赖、配置服务账户密钥、编写推送服务类以及发送消息等步骤,帮助开发者快速实现推送通知功能。
66 2
|
1月前
|
存储 人工智能 Java
将 Spring AI 与 LLM 结合使用以生成 Java 测试
AIDocumentLibraryChat 项目通过 GitHub URL 为指定的 Java 类生成测试代码,支持 granite-code 和 deepseek-coder-v2 模型。项目包括控制器、服务和配置,能处理源代码解析、依赖加载及测试代码生成,旨在评估 LLM 对开发测试的支持能力。
37 1
|
1月前
|
Java BI 调度
Java Spring的定时任务的配置和使用
遵循上述步骤,你就可以在Spring应用中轻松地配置和使用定时任务,满足各种定时处理需求。
131 1
|
14天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
28 0
|
1月前
|
Java Apache Maven
Java/Spring项目的包开头为什么是com?
本文介绍了 Maven 项目的初始结构,并详细解释了 Java 包命名惯例中的域名反转规则。通过域名反转(如 `com.example`),可以确保包名的唯一性,避免命名冲突,提高代码的可读性和逻辑分层。文章还讨论了域名反转的好处,包括避免命名冲突、全球唯一性、提高代码可读性和逻辑分层。最后,作者提出了一个关于包名的问题,引发读者思考。
Java/Spring项目的包开头为什么是com?
下一篇
无影云桌面