首页 > 其他分享 >记一次使用spring事件机制失效排查修复

记一次使用spring事件机制失效排查修复

时间:2024-04-02 11:12:42浏览次数:18  
标签:spring StudentEvent public 排查 事件 studentEvent 失效 监听

前言

在日常业务开发中过程,我们有时候为了业务解耦,会利用spring的机制,就是利用spring提供的ApplicationListener、ApplicationEventMulticaster等核心API来实现。(注: 我这边列的是核心底层API接口,正常我们会用监听事件用@EventListener,发布事件用 applicationContext.publishEvent()或者applicationEventPublisher.publishEvent())

本文案例主要来自团队的小伙伴,在利用spring事件机制踩到的坑。直接以案例的形式来讲解

示例案例

案例场景:当项目启动时,从数据库加载学生数据,并放到本地缓存。为了业务解耦 ,团队小王采用了spring的事件驱动方式来实现。他的实现步骤如下

1、定义学生事件

public class StudentEvent extends ApplicationEvent {
    /**
     * Create a new {@code ApplicationEvent}.
     *
     * @param source the object on which the event initially occurred or with
     *               which the event is associated (never {@code null})
     */
    public StudentEvent(Object source) {
        super(source);
    }
}

2、创建学生事件发布

@Service
@RequiredArgsConstructor
public class StudentServiceImpl extends ServiceImpl<StudentDao, StudentEntity> implements StudentService,InitializingBean {

    private final StudentDao studentDao;
    private final ApplicationContext applicationContext;

    @Override
    public void afterPropertiesSet() throws Exception {
        StudentEvent studentEvent = new StudentEvent(studentDao.listStudents());
        applicationContext.publishEvent(studentEvent);
    }
    @Override
    public List<StudentEntity> listStudents() {
        return studentDao.listStudents();
    }
}

3、创建事件监听

@Component
public class StudentCache {
    private Map<Integer, StudentEntity> studentMap = new ConcurrentHashMap<>();

    @EventListener
    public void listener(StudentEvent studentEvent){
        if(studentEvent.getSource() instanceof List){
            List<StudentEntity> studentEntityList = (List<StudentEntity>) studentEvent.getSource();
            if(studentEntityList != null){
                studentEntityList.forEach(studentEntity -> {
                    studentMap.put(studentEntity.getSId(), studentEntity);
                });
            }
        }

        System.out.println(studentMap);
    }

}

思考题:StudentCache能否正常接收到学生事件?

答案: 接收不到

问题解惑

首先我们要先确认事件监听的观察者,是何时加入事件监听容器?

我们可以从事件监听注解@EventListener入手,通过源码我们可以发现事件监听的观察者,是通过

org.springframework.context.event.EventListenerMethodProcessor#afterSingletonsInstantiated

方法调用加入到事件监听容器,而这个方法的调用时机是在

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons


即在所有非懒加载单例bean加载入spring单例池后才触发调用。而案例中,事件的发布放在

com.github.lybgeek.student.service.impl.StudentServiceImpl#afterPropertiesSet

实现,该方法会比afterSingletonsInstantiated更先执行,而此时事件监听容器还没有该事件的观察者,就会导致事件发布了,但是没有相应观察者进行监听

问题修复

方法有很多种,可以利用spring自带的事件,比如监听ContextRefreshedEvent事件后,再进行事件发布

@EventListener
    public void afterPropertiesSet(ContextRefreshedEvent contextRefreshedEvent) throws Exception {
        StudentEvent studentEvent = new StudentEvent(studentDao.listStudents());
        applicationContext.publishEvent(studentEvent);
    }

也可以利用spring其他扩展点,比如SmartInitializingSingleton,如果是springboot应用,还可以用CommandLineRunner或者ApplicationRunner

总结

本文修复问题的关键其实就是在于对spring一些扩展机制的优先调用顺序的了解

标签:spring,StudentEvent,public,排查,事件,studentEvent,失效,监听
From: https://www.cnblogs.com/linyb-geek/p/17967855

相关文章

  • 基于springboot实现高校心理教育辅导系统项目【项目源码+论文说明】计算机毕业设计
    基于springboot实现高校心理教育辅导系统演示摘要随着Internet技术的发展,心理教育辅导系统应运而生,心理教育辅导系统为用户提供了一个更为便利的心理测试咨询平台。所以,为了充分满足高校学生心理教育辅导的需求,特开发了本高校心理教育辅导系统。本高校心理教育辅导系统的......
  • 基于springboot实现学生读书笔记共享平台系统项目【项目源码+论文说明】
    基于springboot实现学生读书笔记共享平台系统演示摘要本论文主要论述了如何使用JAVA语言开发一个读书笔记共享平台,本系统将严格按照软件开发流程进行各个阶段的工作,采用B/S架构,面向对象编程思想进行项目开发。在引言中,作者将论述读书笔记共享平台的当前背景以及系统开发......
  • 基于springboot实现校园周边美食探索及分享平台系统项目【项目源码+论文说明】
    基于springboot实现园周边美食探索及分享平台系统演示摘要美食一直是与人们日常生活息息相关的产业。传统的电话订餐或者到店消费已经不能适应市场发展的需求。随着网络的迅速崛起,互联网日益成为提供信息的最佳俱渠道和逐步走向传统的流通领域,传统的美食业进而也面临着巨......
  • 基于jsp+Spring boot+mybatis的图书管理系统设计和实现
    基于jsp+Springboot+mybatis的图书管理系统设计和实现博主介绍:多年java开发经验,专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域作者主页央顺技术团队Java毕设项目精品实战案例《1000套》欢迎点赞收藏⭐留言文末获取源码联系方式......
  • 在Linux中,有哪些故障排查和诊断工具?
    在Linux中,有多种故障排查和诊断工具可以帮助管理员和开发者快速定位和解决系统或应用程序中的问题。以下是一些常用的故障排查和诊断工具:dmesg命令:dmesg是一个用于显示内核控制的各种消息的工具,包括硬件状态、驱动加载和系统错误等。通过查看这些消息,管理员可以了解系统启动......
  • @ComponentScan注解 -【Spring底层原理
    案例已上传GitHub,欢迎star:https://github.com/oneStarLR/spring-annotation一、注解用法1.背景知识什么是组件?组件也是抽象的概念,可以理解为一些符合某种规范的类组合在一起就构成了组件,他可以提供某些特定的功能,但实际他们都是类,只不过有他们特殊的规定。组件......
  • 【异常】Spring的依赖注入(DI)系统提示异常,因为漏了一个实现类导致了错误Parameter 0 of
    一、异常内容2024-04-0111:44:39.912[main]ERRORorg.springframework.boot.diagnostics.LoggingFailureAnalysisReporter-***************************APPLICATIONFAILEDTOSTART***************************Description:Parameter0ofconstructorinc......
  • Vmware虚拟机远程SSH连接失效解决方法及分析过程
    问题描述系统为CentOS764位一向能够正常连接在某次使用FinalShell进行远程SSH连接时突然无法连接对问题原因猜测及尝试1.dns解析失效发现显示DNS无法解析,可以得知是使用了主机名登录,而主机名无法登录.遂查看host文件.host文件因不知名原因被清空,重新恢复后该问......
  • IDEA中新建SpringBoot模块,JDK版本问题解决
    问题描述IDEA中新建SpringBoot模块,使用的JAVAJDK1.8,新建模块时选项中没有JDK8: 运行时报错,JDK之类的问题解决方案,查看修改以下四个地方:(1)设置-Java编译器 (2)项目结构--依赖以及源码 ......
  • 10.Mybatis在springboot中的整合总结
    如果你是从事java开发的那数据库绝对是你离不开的东西我以mysql为例好像都是用的这个吧下载就不多bb了直接看springboot整合添加依赖jdbcmysql和mybatis的依赖然后千万别去当当敲代码了你做一步一个验证一步测试一下是否成功加载成功了properties(或者yaml)中配......