Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Quartz with Spring Boot 2

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.

like image 861
ohwelppp Avatar asked May 08 '18 13:05

ohwelppp


People also ask

Does Spring Boot have a scheduler for quartz?

Quartz Scheduler Spring Boot offers several conveniences for working with the Quartz scheduler, including the spring-boot-starter-quartz “Starter”. If Quartz is available, a Scheduler is auto-configured (through the SchedulerFactoryBean abstraction).

How do I create a custom script in spring quartz?

It is also possible to provide a custom script by setting the spring.quartz.jdbc.schema property. To have Quartz use a DataSource other than the application’s main DataSource, declare a DataSource bean, annotating its @Bean method with @QuartzDataSource.

Is it possible to import a spring project into quartz?

It is a Maven project which can be imported and run as-is. The default setting uses Spring's convenience classes, which can be easily switched to Quartz API with a run-time parameter (refer to the README.md in the repository). with Spring?

Can I add a quartz scheduler to an existing repository?

Add a Quartz scheduler to an existing repository, showing just how quick and easily this can be accomplished — thanks to Spring Boot Starters. Join the DZone community and get the full member experience.


3 Answers

You have to add the C3P0 dependency:

<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.2</version>
</dependency>
like image 50
Oliver Raupach Avatar answered Nov 12 '22 13:11

Oliver Raupach


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

like image 38
Adan Amarillas Avatar answered Nov 12 '22 15:11

Adan Amarillas


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.

like image 40
Dheeraj Avatar answered Nov 12 '22 13:11

Dheeraj