spring中的事件发布与监听

点赞再看,养成习惯,微信搜索「 小大白日志」关注这个搬砖人。

文章不定期同步公众号,还有各种一线大厂面试原题、我的学习系列笔记。

spring事件发布与监听的应用场景

当处理完一段代码逻辑,接下来需要同时执行多个任务,有什么好方法呢?如果在微服务项目中,当属MQ莫属了;但如果是单机,spring为我们也提供了[事件发布-监听]机制去处理这种逻辑,主要有@EventListener型和@TransactionalEventListener型两种方式

@EventListener型发布与监听

一般有【实体类+事件类+事件发布类+事件监听类】,以下模拟”添加新用户”后,需要同时进行多个任务为例(异步)

//实体类
@Data
public class User {
    private String name;
    private String operate;
}
//事件类
@Setter
@Getter
public class UserEvent extends ApplicationEvent{  //事件类必须继承ApplicationEvent
    private User user;
    public UserEvent(Object source) {
        super(source);
    }
}
//事件发布类
@Service
@Slf4j
public class UserServiceImpl {
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    public void addUser(){
        User user=new User();
        user.setName("afei");
        user.setOperate("add");
        UserEvent userEvent=new UserEvent(this);
        userEvent.setUser(user);
        insertUser(user);//user入库
        applicationEventPublisher.publishEvent(userEvent);//"事件发布类"发布UserEvent事件以便给"事件监听类"监听到
        log.info("{},发布[添加新用户]事件成功...",Thread.currentThread().getName());
    }

    public void insertUser(User user){}
}
//事件监听类
@Component  //必须让spring扫描到
@Slf4j
public class UserListerner {

    /*
    *执行多任务
    */
    @Async  //@Async可以开启一个异步任务(启动类要加@EnableAsync),因为监听默认是同步的:监听到UserEvent类事件后,执行本方法代码,然后返回原链路继续执行原来的代码;有了@Async就可以以线程的方式异步执行本方法
    @EventListener(value = UserEvent.class,condition = "#userEvent.user.operate=='add'")  //只监听userEvent.user.operate='add'的UserEvent事件,#userEvent与afterAddUser()方法的参数名一致
    public void afterAddUser(UserEvent userEvent){
        try {
            Thread.sleep(300); //停300ms,方便观察异步线程
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        User user=userEvent.getUser();
        log.info("{},监听到[添加新用户]事件:{}",Thread.currentThread().getName(),user.toString());
        //去数据库查询出user并执行多个任务:发邮件、送体验卡..

        bussinessOperate(getUserByUserName(user.getUserName());
    }
    void bussinessOperate(User user){}
}
//启动类
@EnableAsync  //开启对异步任务的支持,开启@EnableAsync之后@Async才能使用
@SpringBootApplication
public class DemoTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoTestApplication.class, args);
    }

}
//测试类
public class TestEvent extends BaseTest{
    @Autowired
    UserServiceImpl userService;

    @Test
    public void test(){
        userService.addUser();
    }
}
//测试基础类
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class BaseTest {
    @Before
    public void before(){
        log.info("单元测试before...");
    }

    @After
    public void after(){
        log.info("单元测试after...");
    }
}

运行后结果:

spring中的事件发布与监听

@TransactionalEventListener型发布与监听

虽然上面@EventListener型解决了单机下多任务的发布监听,但是上面”事件发布”后如果没有提交当前事务,则”事件监听”就去数据库里查询user并执行多个任务,user不存在会报空指针,解决方法是用@TransactionalEventListener保证在”事件发布”后提交了当前事务,才会去执行”事件监听”

//除了事件监听类有点不同,其他代码均与上面一致,事件监听类:
@Component
@Slf4j
public class UserListerner {

    //@EventListener  //单纯监听UserEvent类事件
    @Async  //@Async可以开启一个异步任务(启动类要@EnableAsync),因为监听默认是同步的:监听到UserEvent类事件后,执行下面的代码,然后返回原链路继续执行原来的代码
    @TransactionalEventListener(phase= TransactionPhase.AFTER_COMMIT,fallbackExecution = true)  //phase默认为TransactionPhase.AFTER_COMMIT,它指定了在事件发布的相关事务提交后才会去执行以下监听方法;fallbackExecution默认为false,指如果"事件发布"不存在事务,则不会执行监听方法,如果为true则不管“事件发布”有没有事务,都会执行以下监听方法
    public void afterAddUser(UserEvent userEvent){
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        User user=userEvent.getUser();
        log.info("{},监听到[添加新用户]事件:{}",Thread.currentThread().getName(),user.toString());
        //业务操作:发邮件、送体验卡...

        bussinessOperate();
    }

    void bussinessOperate(){}
}

OK,如果文章哪里有错误或不足,欢迎各位留言。

创作不易,各位的「 三连」是二少创作的最大动力!我们下期见!

Original: https://www.cnblogs.com/mofes/p/15456239.html
Author: 明天喝可乐
Title: spring中的事件发布与监听

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/589739/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 大数据技术栈,主要有哪些

    往大数据方向发展需要学哪些技术?网上一搜真是指不胜屈。对于小白来说,实在是一头雾水,到底哪些是当下流行的?哪些是必须要先学会的?流行?主次搞不清。为了解决这些疑惑,羚羊专门花了些时…

    Java 2023年6月6日
    094
  • 一万了解 Gateway 知识点

    1.什么是 网关 API 网关是一个搭建在客户端和微服务之间的服务,我们可以在 API 网关中处理一些非业务功能的逻辑,例如权限验证、监控、缓存、请求路由等。 网关的核心作用就是路…

    Java 2023年6月5日
    099
  • 删除重复值的结点

    删除重复值的结点 问题重述: 给定一个无序单链表的头节点head,删除其中值重复出现的结点 问题分析: 这道题要删除重复值的结点,我们可以想到哈希表,因为哈希表是无序不重复的,我们…

    Java 2023年6月7日
    066
  • 【每日算法】动态规划一

    斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) = 0,F(1) = 1F…

    Java 2023年6月9日
    082
  • 临时抱佛脚

    临时抱佛jio 需要打的板子 高斯消元 FFT/NTT 拉格朗日插值 LCT splay K-D Tree 二分图/最大流/费用流 后缀数组后缀自动机 可能还需要重新学一下的东西 …

    Java 2023年5月30日
    073
  • 在 Gradle 中使用 MyBatis Generator

    在 Intellij IDEA 中结合 Gradle 使用 MyBatis Generator 逆向生成代码 Info: JDK 1.8 Gradle 2.14 Intellij …

    Java 2023年5月30日
    0105
  • springboot

    狂神说秦疆老师的笔记 Original: https://www.cnblogs.com/zrk0929/p/15878309.htmlAuthor: 学技术的小凯Title: s…

    Java 2023年6月7日
    081
  • [springmvc]ssm框架整合超简单

    此整合没有具体的业务,因为ssm整合最难的点就在于配置文件的整合,因此这里只详细记录配置文件的整合 spring和dao整合将mybatis的配置文件的数据库连接和sqlsessi…

    Java 2023年6月6日
    0103
  • [算法]“简简单单”的插入排序,你还没掌握吗?

    写在前边 大家好,我是melo,一名大二上软件工程在读生,经历了一年的摸滚,现在已经在工作室里边准备开发后台项目啦。不过这篇文章呢,还是想跟大家聊一聊数据结构与算法,学校也是大二上…

    Java 2023年6月5日
    086
  • 大顶堆的实现(基于数组存储的完全二叉树)

    完全二叉树 完全二叉树的定义 满二叉树非完全二叉树,非满二叉树完全二叉树 完全二叉树的特点 叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。 完全二叉树的实现 …

    Java 2023年6月13日
    067
  • Java核心技术-反射

    Day2 利用反射分析类的能力 在Java.lang.reflect包中有三个类Filed Method Constructor,分别用于描述类的字段,方法和构造器。 这三个类有一…

    Java 2023年6月5日
    0124
  • java中将一个list的内容复制给另一个list之后,去新的list进行操作的时候,原来的list也会发生变化

    问题:java中将一个list的内容复制给另一个list之后,去新的list进行操作的时候,原来的list也会发生变化 解决方案:直接采用”=”进行的复制属…

    Java 2023年5月29日
    094
  • Kakfa系列丛书推荐之《深入理解Kafka:核心设计与实践原理》

    pdf格式文档下载见下文 编者推荐 本书从Kafka的基本概念入手,主要从生产端、消费端、服务端等3个方面进行全面的陈述,主要内容包括Kafka的基本使用方式、生产者客户端的使用、…

    Java 2023年6月15日
    080
  • 【紧急】Log4j又发新版2.17.0,只有彻底搞懂漏洞原因,才能以不变应万变,小白也能看懂

    1 事件背景 经过一周时间的Log4j2 RCE事件的发酵,事情也变也越来越复杂和有趣,就连 Log4j 官方紧急发布了 2.15.0 版本之后没有过多久,又发声明说 2.15.0…

    Java 2023年6月7日
    081
  • 11、查看线程状态

    11、线程状态 package com.testthread1; public class TestThread { public static void main(String[…

    Java 2023年6月8日
    088
  • 原型模式详解

    原型模式 1.1原型模式概述 1.1.1原型模式定义 原型模式(Prototype Pattern)指原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象,属于创建型设计模…

    Java 2023年6月7日
    0114
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球