Transactional注解导致Spring Bean定时任务失效

news2024/10/11 22:55:49

背景

业务需要定时捞取数据库中新增的数据做数据处理及分析,更新状态,处理结束。而我们不能随意定义线程池,规定使用统一的标准规范来定义线程池。如在配置文件中配置线程池的属性:名称,线程核心数等,任务属性:任务名称,任务处理类,延迟信息等等。定义好这些信息后,启动系统时,线程池就会初始化并开始执行任务。

业务实现

  • Spring监听器
    使用Spring容器启动结束发布的ApplicationReadyEvent事件来初始化线程池。
	@EventListener
    public void onApplicationReadyEvent(ApplicationReadyEvent event) {
        log.info("监听器启动线程池。。。");
        jobManager.start();
    }
  • 线程池统一处理类
   public void start() {
       AbstractJob job = context.getAutowireCapableBeanFactory().createBean(BusinessJob.class);
       threadPool.scheduleWithFixedDelay(job, 1000, 1000, TimeUnit.MILLISECONDS);
   }
  • 任务处理抽象类
    所有任务都会继承这个抽象类,它定义了一些公共的行为,比如看门狗监视任务是否正常执行。看门口属性被定义为这个抽象类的属性,它是直接导致任务失效的直接原因
    @Override
    public void run() {
        log.info("==========AbstractJob start===========");
        try {
            work();
            watchDog.print();
        } catch (Throwable t) {
            logger.log(Level.WARNING, "aaa bbb ccc", t);
        }
        log.info("==========AbstractJob end=============");
    }

    protected abstract void work();
  • 任务处理类(继承上面的抽象类)
    该类被定义为Spring Bean对象
	@Override
    public void work() {
        log.info("job start.");
        handle();
        log.info("job end.");
    }
    
    public void handle(){
        // 处理业务
    }

新需求

由于某种原因业务提出新需求,而这个需求需要支持事务,于是根据以前学过的知识,直接在任务处理类中定义@Transactional注解的方法,通过Spring循环依赖,注入了自己。

	@Override
    public void work() {
        log.info("job start.");
        handle();
        // job
        job.testTransaction();
        log.info("job end.");
    }
	
	@Transactional
    public void testTransaction() {
        log.info("execute transaction.");
        jdbcTemplate.execute("update user set name='rick1' where id = 3");
//        jdbcTemplate.execute("insert into user values('1', 'rick')");
        log.info("execute transaction end.");
    }

本地测试发现执行正常,提交代码。
万万没想到,测试反馈,定时任务只跑了一次就停止了,也没有异常信息
也是本地重新启动发现确实跑了一次任务就停了。于是将@Transactional注解干掉,任务正常的执行。所以将事务方法重新定义一个类,加上@Component注解,通过bean对象引入到任务类中。
至此,业务是开发完了,但是出现这种问题的原因还没有分析清楚,随后就有了上面的demo复现问题。

猜测

@Transactional注解原理是生成一个代理对象包裹原生创建的Bean对象,是不是启动时生成的代理对象将原来传递到线程池的任务被丢弃了。于是把所有涉及的源码开始分析起来

  • 获取任务添加到线程池
    从Spring容器中获取的Bean对象是个代理对象,所以线程池里面执行的任务是个代理对象
    在这里插入图片描述
  • ScheduledThreadPoolExecutor线程池
    执行scheduleWithFixedDelay()方法
    • 检验
    • 封装任务
    • 调用delayedExecute()方法执行任务,最终调用ThreadPoolExecutor类ensurePrestart()方法,将任务提交到线程池执行
      在这里插入图片描述
      线程池启动线程执行的是ScheduledThreadPoolExecutor内部类的ScheduledFutureTask类run()方法
      在这里插入图片描述
      第一次执行任务时调用的是runAndReset()方法,如果任务执行成功,则返回true,通过reExecutePeriodic()将任务重新添加到线程池去执行;如果任务执行失败抛异常,则返回false,任务就被丢弃了,也就是跑一次,后面就不跑了。
      在这里插入图片描述
      顺着这个思路返回去看任务执行过程,如果抛异常了,那就证明这个迷就解开了。c.call()就会调用我们定义的任务抽象类,它又会调用work()方法,而从日志得知work()正常执行完成,所以问题极大可能出现在抽象类里面,work()执行完了以后调用watchDog对象的方法,此时Debug发现watchDog对象为空,也就出现了空指针异常,这个异常会被捕获,并打印出来,此时又离谱的事来了,任务类的代理对象的logger属性又是空的,所以又出现了空指针异常抛出去了,导致任务停止执行。

为什么代理对象的属性都为空呢

Spring代理对象所有属性都为空,只有被代理对象的属性有值。可以参考这篇文章

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2206144.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用最短长度的绳子把整个花园围起来

给定一个数组 trees,其中 trees[i] [xi, yi] 表示树在花园中的位置。 你被要求用最短长度的绳子把整个花园围起来,因为绳子很贵。只有把 所有的树都围起来,花园才围得很好。 返回恰好位于围栏周边的树木的坐标。 示例 1: 输入: points […

白鲨优化算法(WSO)的MATLAB代码复现

目录 1 白鲨优化算法优化BP神经网络代码复现 2 白鲨优化算法优化支持向量机代码复现 3 白鲨优化算法优化长短期记忆神经网络代码复现 1 白鲨优化算法优化BP神经网络代码复现 1)单输出回归预测:单输出回归预测:大白鲨算法优化BP神经网络模…

OpenCV HoughLine()函数与HoughlinesP()函数及HoughCircles()函数详解及用法示例

OpenCV HoughLine()函数与HoughlinesP()函数都用于图像中的直线检测,但二者是有区别的。 HoughLine()函数 HoughLines()基于霍夫变换的原理,通过投票机制来确定图像中直线的存在及其参数。该函数返回检测到的直线的极坐标参数。它…

【多线程】CAS原理

文章目录 为什么会出现CAS思想?CAS概念CAS自旋概念CAS的简单使用CAS源码解析 UnSafe类CAS底层原理CAS的硬件保证CAS自旋锁的实现前置知识----原子引用AtomicReference实现自旋锁 CAS缺点ABA问题什么是ABA问题如何解决ABA问题简单案例AtomicStampedReference的源码分析 为什么会…

leetcode链表(二)-两两交换链表中的节点

题目 . - 力扣(LeetCode) 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 思路 一定要使用虚拟头节点…

电子学报期刊投稿过程记录

电子学报的编辑老师确实人非常好,专业知识过硬,文章内容审核仔细,对格式的要求相对严格,并且打电话或者邮箱询问都很和善,也很温柔,同时也愿意配合再缴费后提前发送录用证明,但是见刊和网络首发…

单点登录Apereo CAS 7.1客户端集成教程

从上一篇部署并成功运行CAS服务端后,我们已经能通过默认的账号密码进行登录。 上篇地址:单点登录Apereo CAS 7.1安装配置教程-CSDN博客 本篇我们将开始对客户端进行集成。 CAS中的客户端,就是指我们实际开发的各个需要登录认证的应用。现在,跟着笔者的步伐,一起探索如何…

共识算法Raft

引入 在分布式系统中,为了消除单点提高系统可用性,通常会创建副本来进行容错,但这会带来另一个问题就是,如何保证多个副本之间的数据一致性。 为了解决这个问题,计算机行内就提出了共识算法,它允许多个分…

git gui基本使用

一、图形化界面 二、创建新项目 创建文件,加入暂存区,提交到版本库 三、创建分支 四、合并分支 1.切换至master 五、更新分支 六、解决冲突 修改冲突,加入暂存区,提交到版本库 七、远程创建库 Gitee - 基于 Git 的代码托管和研…

低功耗

低功耗 目录 低功耗 STM32中的电源系统 STM32 中的低功耗 相关代码 -- 首先我们先看我们做的项目如何降低功耗 -- 对于设备,功耗怎么降低?把设备上所有的电子模块,都进入低功耗模式。 对于空气质量检测仪,如何降低功耗&…

修改armbian DNS服务器地址(永久修改DNS配置)

linux dns服务器地址的配置文件在/etc/resolv.conf 但系统可能设置的是默认值,也就是192.168.1.1。导致系统无法正常解析域名,进而导致有一些接口无法调用或下载失败。 最直接的思路就是修改/etc/resolv.conf,将其中的nameserver修改为正确的…

必看系列:面试官通过一个问题考查了网络编程所有知识点!

一、写在开头 本文的主题是和大家一起探讨学习:“在浏览器中输入URL开始后,计算机所做的几件事”,这个问题是好几年前自己面试的时候,面试官考问过的,当时准备十分不充分,回答的一塌糊涂,今天拿出来再整理学习一遍,一同进步! 其实这个问题本身倒是不难,但它巧妙的是…

节假日提醒,节假日任务,节假日判断如何做?这篇文章教会你!

你是否有这样的需求,有一个任务需要在大家都休息的时候处理,你肯定会想到周六周日了,那不好意思,遇到调休怎么办呢?遇到国假怎么办呢?我这里所说的节假日和工作日不仅仅指正常的周一至周日,还包…

浙江省发规院产业发展研究所调研组莅临迪捷软件考察调研

2024年10月10日下午,浙江省发展与规划院产业发展研究所调研组一行莅临迪捷软件考察调研,绍兴市府办、区发改、区经信、迪荡街道等相关领导陪同。 调研组一行参观了迪捷软件的展厅与办公区,深入了解了迪捷软件的公司发展历程、运营状况、产品…

Python 如何使用 Bert 进行中文情感分析

前言 在自然语言处理(NLP)领域,情感分析是一个非常常见且重要的应用。情感分析通常用于识别文本中的情感,例如判断一条微博或评论是正面、负面还是中性。在过去的几年中,随着深度学习的发展,BERT&#xff…

MySQL表的基本操作和数据类型

MySQL表的基本操作和数据类型 表的操作创建表修改表删除表 数据类型数值类型整型浮点型 文本、二进制类型日期时间类型ENUM类型和SET类型 表的操作 创建表 语法: CREATE TABLE table_name(field1 datatype,field2 datatype,field3 datatype )character set 字符集…

Python的matplotlib可视化工具基本操作(数据分析生成图表)

一、安装导入 1、使用包管理器安装matplotlib pip3 install matplotlib 2、导入plt工具 import matplotlib.pyplot as plt 二、基本函数 1、创建图表 使用pyplot工具打点调用创建图表函数 例如创建直方图: import matplotlib.pyplot as plt import pandas…

【unity框架开发9】序列化字典,场景,vector,color,Quaternion

文章目录 前言一、可序列化字典类普通字典简单的使用可序列化字典简单的使用 二、序列化场景三、序列化vector四、序列化color五、序列化旋转Quaternion完结 前言 自定义序列化的主要原因: 可读性:使数据结构更清晰,便于理解和维护。优化 I…

Android Framework默认授予app通知使用权限

安卓通知使用权限 在安卓系统中,应用程序需要获取通知使用权限才能向用户发送通知。以下是关于安卓通知使用权限的一些信息: 权限获取方式 当用户安装应用时,系统可能会在安装过程中提示用户授予应用通知权限。用户可以选择允许或拒绝。 应…

记录一些yolo-world训练数据集的报错

参考的这个文章 https://blog.csdn.net/ITdaka/article/details/138863017?spm1001.2014.3001.5501 openai快捷下载:https://download.csdn.net/download/qq_43767886/89876720 然后我打算训练coco数据集,遇到了以下的问题 问题一 原因:…