9

Trying to update my project from Spring Boot 1.5.8 to 2.0.1 and having problems with Quartz. I used Spring BOM and have Quartz 2.3.0 version.

Here is my QuartzConfigurer that sets up beans for Spring:

import lombok.extern.slf4j.Slf4j;
import org.quartz.JobDetail;
import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

import javax.annotation.PostConstruct;

@Slf4j
@Configuration
public class QuartzConfigurer {

    @Value("${quartz.cron.contract-status}")
    private String contractCron;

    @Value("${quartz.config-filename}")
    private String quartzConfigFileName;

    @Autowired
    private ApplicationContext applicationContext;

    @PostConstruct
    public void init() {
        log.debug("Initialization of quartz configurer");
    }

    @Bean
    public SpringBeanJobFactory springBeanJobFactory() {
        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
        jobFactory.setApplicationContext(applicationContext);
        return jobFactory;
    }

    @Bean
    public SchedulerFactoryBean scheduler(Trigger trigger, JobDetail job) {
        SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
        schedulerFactory.setConfigLocation(new ClassPathResource(quartzConfigFileName));

        schedulerFactory.setJobFactory(springBeanJobFactory());
        schedulerFactory.setJobDetails(job);
        schedulerFactory.setTriggers(trigger);
        return schedulerFactory;
    }

    @Bean
    public JobDetailFactoryBean jobDetail() {
        JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
        jobDetailFactory.setJobClass(ContractStatusJob.class);
        jobDetailFactory.setName("Qrtz_Contract_Job_Detail");
        jobDetailFactory.setDescription("Invoke contract job detail");
        jobDetailFactory.setDurability(true);
        return jobDetailFactory;
    }

    @Bean
    public CronTriggerFactoryBean trigger(JobDetail job) {
        CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
        trigger.setJobDetail(job);

        log.debug("Configuring trigger to fire based on cron {}", contractCron);
        trigger.setCronExpression(contractCron);
        trigger.setName("Qrtz_Contract_Trigger");
        return trigger;
    }
}

Here is AutowiringSpringBeanJobFactory used in above file:

import lombok.extern.slf4j.Slf4j;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

@Slf4j
public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

    private transient AutowireCapableBeanFactory beanFactory;

    @Override
    public void setApplicationContext(final ApplicationContext context) {
        beanFactory = context.getAutowireCapableBeanFactory();
    }

    @Override
    protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
        final Object job = super.createJobInstance(bundle);
        beanFactory.autowireBean(job);
        return job;
    }
}

And here is quartz.properties used with Spring Boot 1.5.8 that was working properly. This is a property file used in QuartzConfigurer:

    #============================================================================
# Configure Main Scheduler Properties
#============================================================================

org.quartz.scheduler.instanceName = MyClusteredScheduler
org.quartz.scheduler.instanceId = AUTO

#============================================================================
# Configure ThreadPool
#============================================================================

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 25
org.quartz.threadPool.threadPriority = 5

#============================================================================
# Configure JobStore
#============================================================================

org.quartz.jobStore.misfireThreshold = 60000

org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = default
org.quartz.jobStore.tablePrefix = QRTZ_

org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000

#============================================================================
# Configure Datasources
#============================================================================

org.quartz.dataSource.default.driver = org.postgresql.Driver
org.quartz.dataSource.default.URL = jdbc:postgresql://localhost:5432/example
org.quartz.dataSource.default.user = postgres
org.quartz.dataSource.default.password = postgres
org.quartz.dataSource.default.maxConnections = 5
org.quartz.dataSource.default.validationQuery = select 0 from dual

Here is exception thrown when starting up Application:

    2018-05-08 15:26:52.855  INFO 21200 --- [  restartedMain] o.s.s.quartz.SchedulerFactoryBean        : Loading Quartz config from [class path resource [quartz.properties]]
2018-05-08 15:26:52.873  INFO 21200 --- [  restartedMain] org.quartz.impl.StdSchedulerFactory      : Using ConnectionProvider class 'org.quartz.utils.C3p0PoolingConnectionProvider' for data source 'default'
2018-05-08 15:26:52.874  WARN 21200 --- [  restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scheduler' defined in class path resource [com/onwelo/vendormanagement/core/configuration/quartz/QuartzConfigurer.class]: Invocation of init method failed; nested exception is org.quartz.SchedulerException: Could not initialize DataSource: default [See nested exception: org.quartz.SchedulerException: ConnectionProvider class 'org.quartz.utils.C3p0PoolingConnectionProvider' could not be instantiated. [See nested exception: java.lang.reflect.InvocationTargetException]]

My database configuration didn't change at all and it's working fine with Spring Boot 1.5.8.

1

3 Answers 3

14

You have to add the C3P0 dependency:

<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.2</version>
</dependency>
1
  • This fixed my issue. Thank you! Commented Mar 7, 2019 at 14:17
11

Configure Quartz to use HikariCP (default is c3p0)

# quartz.properties

org.quartz.dataSource.quartzDataSource.provider=hikaricp

For more: https://github.com/quartz-scheduler/quartz/wiki/How-to-Use-DB-Connection-Pool

1

I had the same issue sometime back. It is clearly due to the absence of the 'c3p0' dependency.

https://mvnrepository.com/artifact/c3p0/c3p0
compile group: 'c3p0', name: 'c3p0', version: '0.9.1.2'

I have added the below dependency into my build.gradle file and then refreshed the dependencies. Then this error is gone.

Not the answer you're looking for? Browse other questions tagged or ask your own question.