[spring-projects/spring-boot]2.6.6 quartz 数据源升级问题

2024-06-26 739 views
9

我们有一个 Spring Boot 应用程序从 1.5.9.RELEASE 升级到 2.6.6 版本。该应用程序使用自动配置数据源的 quartz 调度程序和数据库持久性。升级到 2.6.6 后,似乎在初始化 quartz 时不再注入数据源(?),并且在尝试初始化 SchedulerFactoryBean 时失败

这与 2.5.7 升级类似,石英数据源存在问题 #28846

2.6.6 中的异常

Invocation of init method failed; nested exception is org.quartz.SchedulerConfigException: DataSource name not set. 

java.sql.SQLException: There is no DataSource named 'null'
    at org.quartz.utils.DBConnectionManager.shutdown(DBConnectionManager.java:135)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.shutdown(JobStoreSupport.java:741)
    at org.quartz.core.QuartzScheduler.shutdown(QuartzScheduler.java:760)
    at org.quartz.impl.StdSchedulerFactory.shutdownFromInstantiateException(StdSchedulerFactory.java:1372)
    at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:1356)
    at org.quartz.impl.StdSchedulerFactory.getScheduler(StdSchedulerFactory.java:1519)
    at org.springframework.scheduling.quartz.SchedulerFactoryBean.createScheduler(SchedulerFactoryBean.java:679)
    at org.springframework.scheduling.quartz.SchedulerFactoryBean.prepareScheduler(SchedulerFactoryBean.java:616)
    at org.springframework.scheduling.quartz.SchedulerFactoryBean.afterPropertiesSet(SchedulerFactoryBean.java:504)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1389)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1309)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:656)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:639)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:740)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:415)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)

回答

6

@mtsmel 请参阅相关问题的评论org.quartz.jobstore.class。您是否按照该问题顶部的示例设置了配置,如果是,删除该设置是否可以解决您的问题?

2

谢谢斯科特……

不,我们没有在 yml 文件中设置 jobstore.class。

石英:已启用:真

这个 CRON 表示每天凌晨 3 点运行
toaNightlyCron: 0 0 3 * * ?
pastDueCriticalActivitiesCron: 0 0 0 1 1 ? 2100

我们的 QuartzConfig 类中确实有这种“定制”:

@Autowired
private DataSource dataSource;

@Bean
public SchedulerFactoryBean quartzScheduler() {
    SchedulerFactoryBean quartzScheduler = new SchedulerFactoryBean();
    quartzScheduler.setDataSource(this.dataSource);
    quartzScheduler.setTransactionManager(transactionManager);
    quartzScheduler.setOverwriteExistingJobs(true);
    quartzScheduler.setSchedulerName("pete-quartz-scheduler");

    // custom job factory of spring with DI support for @Autowired!
    AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
    jobFactory.setApplicationContext(applicationContext);
    quartzScheduler.setJobFactory(jobFactory);

    quartzScheduler.setQuartzProperties(quartzProperties());

我们是否应该从 QuartzConfig 类中删除上面的几行?

5

注释掉这些行并不能修复错误:

AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory(); jobFactory.setApplicationContext(applicationContext); quartzScheduler.setJobFactory(jobFactory);

6

我将删除整个quartzScheduler()配置方法,并将其替换为 Spring Boot 自动配置使用的属性(请参阅文档代码)。如果您需要进一步自定义SchedulerFactoryBeanBoot 自动配置创建的内容,您可以创建一个SchedulerFactoryBeanCustomizer

6

好的,谢谢。。我会尝试一下……

2

如果您希望我们查看此问题,请提供所需信息。如果未在接下来的 7 天内提供信息,此问题将被关闭。

2

由于缺少所需反馈而关闭。如果您希望我们查看此问题,请提供所需信息,我们将重新打开此问题。

4

那么解决方法是将其包含在 yaml 中?

Spring:
  quartz:
    properties.org.quartz:
      dataSource:
        XXXX:

如果我不想在 yaml 中包含 2 次数据源怎么办?这对维护来说不太好。

6

@fecogc 如果不知道您正在解决的问题是什么,就无法说清楚。如果您将 Spring Boot 的自动配置与 JDBC 作业存储结合使用,则 Quartz 将配置为使用上下文,而DataSource无需您执行任何操作。如果您想使用 Quartz 特定的Datasource,您可以定义一个并按照文档中的说明@Bean注释其方法。@QuartzDataSource

4

@wilkinsona 我修复了这个问题,你可以关闭它了。谢谢

我删除了自定义数据源。并添加到 quartz.properties 中 org.quartz.jobStore.class=org.springframework.scheduling.quartz.LocalDataSourceJobStore

3

仅供参考,此代码对 SchedulerFactoryBean.java 进行了重大更改

        mergedProps.setProperty(StdSchedulerFactory.PROP_JOB_STORE_CLASS, LocalDataSourceJobStore.class.getName());

到此代码 ->

        mergedProps.putIfAbsent(StdSchedulerFactory.PROP_JOB_STORE_CLASS, LocalDataSourceJobStore.class.getName());

这破坏了我的升级,因为新的升级在我们不知情的情况下开始使用“org.quartz.jobStore.class -> org.quartz.impl.jdbcjobstore.JobStoreTX”,这完全不起作用,并且会在 dsName== null 检查时失败 :( 其中另一个作业执行了一些初始化操作,设置了 JobStoreTX 缺少的 dsName。

9

@deantray 请关注本期中描述的链接,它已经解释了所有这些内容。