Qaurtz报错:org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named‘xx‘available
目录NoSuchBeanDefinitionException报错解决NoSuchBeanDefinitionException报错原因分析1.容器未实例化指定类2.Qaurtz前台页面,bean名称配置错误3.Qaurtz框架在非集群环境下,使用同一个数据库,部署了多个版本的代码(重点)结语NoSuchBeanDefinitionException报错解决关于Qaurtz定时框架的运行原理,在文
目录
NoSuchBeanDefinitionException报错解决
NoSuchBeanDefinitionException报错原因分析
3.Qaurtz框架在非集群环境下,使用同一个数据库,部署了多个版本的代码(重点)
NoSuchBeanDefinitionException报错解决
关于Qaurtz定时框架的运行原理,在文章《Qaurtz定时框架,是怎么运行的(源码讲解)》中有详细讲解,自以为对Qaurtz框架的核心功能有了一个全面的了解,谁知在具体做项目的过程中,还是会遇到一些莫名其妙的问题。
首先申明,关于NoSuchBeanDefinitionException的报错的原因其实很简单:就是在Spring框架的Ioc容器中没有我们需要的bean实例。通常我们是根据bean的name去Ioc容器获取其bean实例的:
@Component("updateEmployeeInfoTask")
public class UpdateEmployeeInfoTask implements ITask {
...
比如上图这个段伪代码就是通过@Component注解,把类加载到Ioc容器中,在项目运行成功以后,我们可以通过Spring容器中的ApplicationContext的getBean方法来获取UpdateEmployeeInfoTask类的实例,其在Ioc容器中的id就是其类名的首字母小写,也就是updateEmployeeInfoTask ,但是由于我们使用了@Component的value,所以我们可以在注解后面自定义我们在Ioc容器中的id名,当然这里我们填的和默认的id保持一致,也可以自定义。
NoSuchBeanDefinitionException报错原因分析
以UpdateEmployeeInfoTask类举例分析,关于NoSuchBeanDefinitionException的报错原因, 也就是在容器中找不到这个实例,其原因有如下几点:
1.容器未实例化指定类
比如忘记写@Component注解或者类似的注解,导致类未加入Ioc容器,还有可能是写了注解,但是包和Springboot启动类不在同一个根目录下,还有可能在配置注解中把当前类的包给排除扫描了。当然,这一类情况是最简单的,我们不过多描述,大家可自行排查。
2.Qaurtz前台页面,bean名称配置错误
Qaurtz框架当然离不开前台页面,由于笔者采用的是根据bean的id来获取需要运行的定时任务实例,如果配置了一个原本不存在bean的id,也会导致出现NoSuchBeanDefinitionException报错。
以上图为例,本来是要配置成updateEmployeeInfoTask,结果写错了配置成了updateEmployeeInfoTaskxx,也会出现报错。
3.Qaurtz框架在非集群环境下,使用同一个数据库,部署了多个版本的代码(重点)
关于前面2种情况,都是最基础的,这一种情况才是笔者真实遇到的情况。
在分析问题之前,我们先介绍一下项目背景,只有这样大家才能对整件事情有一个完整的了解。
事情的起因是由于一个公司的孵化项目,使用了Qaurtz定时框架,由于不同的使用场景,部署了2个版本,且分别部署在2台服务器,但是却使用了同一个数据库。
理论上来说,如果Qaurtz框架没有使用集群部署的情况下,是不能多个项目使用同一个数据库的,因为Qaurtz框架的核心原理便是应用服务器有一个后台线程,在项目启动之后,每隔一段时间就对数据库的Qaurtz后台表进行扫描,当获取到满足条件的定时任务时,便执行任务。
在集群环境下,即使部署多个应用服务也是不影响的,但是我们采用了非集群形式,至于原因,我们在另一篇文章有提到。
问题的关键在于采用了非集群的部署方式,且2台应用服务器部署的代码版本不一样,简单来说就是第一台服务器版本为v0,第二台服务器版本为v1,v1包含v0版本的代码,但是v0不包含v1部分代码,我们假设v1在v0的基础上新建了一个testTask。
这时候v0服务器的Qaurtz后台线程在扫描数据库表的时候,可能就会扫描到v1新建的定时任务testTask,但是v0的Ioc容器钟,肯定是找不到这个bean的。
于是就会出现两个很奇怪的现象:明明v1部署了最新的代码,执行定时任务的时候,有时候可以执行成功,有时候又会执行失败;还有一个现象是,有时候定时任务的logger日志都不会打印。
当没有意识到v0还部署着一套应用的时候,笔者都对自己的Java世界观产生了动摇:spring的Ioc容器种获取同一个bean实例,怎么会时有时无?logger.info级别的日志为什么也会时有时无的打印?而且本地调试明明运行的很好,只要部署到服务器就不行了。
关键是自己反复的检查代码,也没发现哪里有问题。
是自己对Spring框架哪里理解不到位,还是说代码哪里写错了?经过无数次的尝试,始终是不得门而入。
等到休息了一晚上,第二天去网上搜了一下,看到了类似的情况,才想起来是不是多套代码对应了一个数据库。
结语
关于v0、v1版本的问题,其实无论是源码分析还是功能分析,自己都弄的比较清楚了,但是在实际的工程实践中还是会出现各种各样的问题,只能说学无止境,问题无止境。
更多推荐
所有评论(0)