背景
最近在做一个项目,需要使用定时任务,打算直接用我以前搭的springboot集成quartz的demo,地址:https://gitee.com/zhanpg/springboot-quartz,结果一直报错。
错误提示
java.lang.IllegalStateException: Active Scheduler of name ‘OneknowClusteredScheduler’ already registered in Quartz SchedulerRepository. Cannot create a new Spring-managed Scheduler of the same name!
找bug
- 开始网上搜索这种错误,发现根本没有,没办法,只能靠自己了。
- 错误里提示‘OneknowClusteredScheduler’已经存在,这个是我在quartz配置文件里配的scheduler实例名,那就从这个开始入手。
- 首先找出这个错误提示在源码的哪个地方
try {
SchedulerRepository repository = SchedulerRepository.getInstance();
synchronized(repository) {
Scheduler existingScheduler = schedulerName != null ? repository.lookup(schedulerName) : null;
Scheduler newScheduler = schedulerFactory.getScheduler();
if (newScheduler == existingScheduler) {
throw new IllegalStateException("Active Scheduler of name '" + schedulerName + "' already registered in Quartz SchedulerRepository. Cannot create a new Spring-managed Scheduler of the same name!");
}
if (!this.exposeSchedulerInRepository) {
SchedulerRepository.getInstance().remove(newScheduler.getSchedulerName());
}
var10 = newScheduler;
}
} finally {
if (overrideClassLoader) {
currentThread.setContextClassLoader(threadContextClassLoader);
}
}
当newScheduler和existingScheduler相同时,就会报这个错,debug到这里
两个确实相同;接着找原因,
Scheduler existingScheduler = schedulerName != null ? repository.lookup(schedulerName) : null;
这里提示schedulerName=OneknowClusteredScheduler,所以existingScheduler=repository.lookup(schedulerName);对比原来项目,debug到这里,发现schedulerName=SchedulerFactory;应该就是这个schedulerName的问题了;schedulerName是这个类SchedulerFactoryBean的属性;在QuartzConfig中有定义这个bean:
@Bean("SchedulerFactory")
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setQuartzProperties(quartzProperties());
return factory;
}
应该是初始化这个bean的时候设置了这个值,
这个方法中,首先调用afterPropertiesSet()这个方法,此方法中又调用prepareSchedulerFactory(),里面又调用initSchedulerFactory方法,此时schedulerName还是null,这个方法中最后
if (this.schedulerName != null) {
mergedProps.setProperty("org.quartz.scheduler.instanceName", this.schedulerName);
} else {
String nameProp = mergedProps.getProperty("org.quartz.scheduler.instanceName");
if (nameProp != null) {
this.schedulerName = nameProp;
} else if (this.beanName != null) {
mergedProps.setProperty("org.quartz.scheduler.instanceName", this.beanName);
this.schedulerName = this.beanName;
}
}
当schedulerName=null时,schedulerName取得是配置文件中instanceName,就是OneknowClusteredScheduler,看着没毛病,接着去原来项目中debug到这里,重大发现,原来项目中此处得代码
if (this.schedulerName != null) {
mergedProps.setProperty("org.quartz.scheduler.instanceName", this.schedulerName);
}
就这么多,没了。事情还没结束,原来项目到这里schedulerName是有值的,为啥现在项目到这里schedulerName是null呢,继续找问题,最后发现在项目中
//现在项目
public void setBeanName(String name) {
this.beanName = name;
}
//原来项目
public void setBeanName(String name) {
if (this.schedulerName == null) {
this.schedulerName = name;
}
}
在给beanName赋值时,原项目已经给schedulerName赋值了,但是现在项目中没有,问题终于找到了。
解决bug
现在项目和原来项目的springboot版本不一致,由于引的quartz包是直接用spring-boot-starter-quartz,这就导致了quartz版本也不一样,解决这个问题,只能换springboot版本了,或者单独引quartz的包。