VOOZH about

URL: https://www.javacodegeeks.com/2016/06/integrating-quartz-spring.html

⇱ Integrating Quartz with Spring - Java Code Geeks


When it comes to scheduling jobs in a java application, Quartz is the first tool that comes into consideration.
Quartz is job scheduler backed up by most popular RDBMSes. It is really convenient and gets integrated with spring quite easy.
In order to create the quartz schema you have to download the quartz distribution and extract the folder located in quartz-2.2.3/docs/dbTables/

Choose the quartz schema according to the database that you use. In our case we will use a local h2 database therefore I will use the tables_h2.sql schema.
In order to avoid any manual sql actions i will use the Spring boot database initialization feature.

Let’s start with our gradle file.

group 'com.gkatzioura'
version '1.0-SNAPSHOT'

apply plugin: 'java'

sourceCompatibility = 1.8

buildscript {
 repositories {
 mavenCentral()
 }
 dependencies {
 classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.3.RELEASE")
 }
}

apply plugin: 'idea'
apply plugin: 'spring-boot'

repositories {
 mavenCentral()
}

dependencies {
 compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '1.3.3.RELEASE'
 compile group: 'org.springframework', name: 'spring-context-support', version: '4.2.4.RELEASE'
 compile group: 'org.springframework', name:'spring-jdbc', version: '4.2.4.RELEASE'
 compile group: 'org.quartz-scheduler', name: 'quartz', version: '2.2.3'
 compile group: 'ch.qos.logback', name: 'logback-core', version:'1.1.3'
 compile group: 'ch.qos.logback', name: 'logback-classic',version:'1.1.3'
 compile group: 'org.slf4j', name: 'slf4j-api',version:'1.7.13'
 compile group: 'com.h2database', name: 'h2', version:'1.4.192'
 testCompile group: 'junit', name: 'junit', version: '4.11'
}

Apart from the quartz, spring and h2 dependencies, we add the spring-jdbc dependencies since we want to have the database initialized through spring.

We will also add an application.yml file

spring:
 datasource:
 continueOnError: true
org:
 quartz:
 scheduler:
 instanceName: spring-boot-quartz-demo
 instanceId: AUTO
 threadPool:
 threadCount: 5
job:
 startDelay: 0
 repeatInterval: 60000
 description: Sample job
 key: StatisticsJob

Due to the schema creation statements (lack of create if not exists statements), I set spring.datasource.continueOnError to false. According to your implementation the workaround will vary.

The application class

package com.gkatzioura.springquartz;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

/**
 * Created by gkatzioura on 6/6/16.
 */
@SpringBootApplication
public class Application {

 public static void main(String[] args) {

 SpringApplication springApplication = new SpringApplication();
 ApplicationContext ctx = springApplication.run(Application.class,args);
 }
}

The h2 datasource configuration neeeded by quartz

package com.gkatzioura.springquartz.config;

import org.h2.jdbcx.JdbcDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

/**
 * Created by gkatzioura on 6/6/16.
 */
@Configuration
public class QuartzDataSource {

 //Since it a test database it will be located at the temp directory
 private static final String TMP_DIR = System.getProperty("java.io.tmpdir");

 @Bean
 public DataSource dataSource() {

 JdbcDataSource ds = new JdbcDataSource();
 ds.setURL("jdbc:h2:"+TMP_DIR+"/test");

 return ds;
 }

}

In our case we want to sent β€˜spam’ emails every minute, therefore we define a simple email service

package com.gkatzioura.springquartz.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * Created by gkatzioura on 6/7/16.
 */
@Service
public class EmailService {

 private static final Logger LOGGER = LoggerFactory.getLogger(EmailService.class);

 public void sendSpam() {

 LOGGER.info("Should send emails");
 }

}

I will also implement a SpringBeanJobFactory

package com.gkatzioura.springquartz.quartz;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

/**
 * Created by gkatzioura on 6/7/16.
 */
public class QuartzJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

 private transient AutowireCapableBeanFactory beanFactory;

 @Override
 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

 beanFactory = applicationContext.getAutowireCapableBeanFactory();
 }

 @Override
 protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {

 final Object job = super.createJobInstance(bundle);
 beanFactory.autowireBean(job);
 return job;
 }
}

QuartzJobFactory will create the job instance and the will use the application context in order to inject any dependencies defined.

Next step is defining our job

package com.gkatzioura.springquartz.job;

import com.gkatzioura.springquartz.service.EmailService;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Created by gkatzioura on 6/6/16.
 */
public class EmailJob implements Job {

 @Autowired
 private EmailService cronService;

 @Override
 public void execute(JobExecutionContext context) throws JobExecutionException {

 cronService.sendSpam();
 }
}

Last step is adding quartz config

package com.gkatzioura.springquartz.config;


import com.gkatzioura.springquartz.job.EmailJob;
import com.gkatzioura.springquartz.quartz.QuartzJobFactory;
import org.quartz.SimpleTrigger;
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.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;

import javax.sql.DataSource;
import java.util.Properties;

/**
 * Created by gkatzioura on 6/7/16.
 */
@Configuration
public class QuartzConfig {

 @Value("${org.quartz.scheduler.instanceName}")
 private String instanceName;

 @Value("${org.quartz.scheduler.instanceId}")
 private String instanceId;

 @Value("${org.quartz.threadPool.threadCount}")
 private String threadCount;

 @Value("${job.startDelay}")
 private Long startDelay;

 @Value("${job.repeatInterval}")
 private Long repeatInterval;

 @Value("${job.description}")
 private String description;

 @Value("${job.key}")
 private String key;

 @Autowired
 private DataSource dataSource;

 @Bean
 public org.quartz.spi.JobFactory jobFactory(ApplicationContext applicationContext) {

 QuartzJobFactory sampleJobFactory = new QuartzJobFactory();
 sampleJobFactory.setApplicationContext(applicationContext);
 return sampleJobFactory;
 }

 @Bean
 public SchedulerFactoryBean schedulerFactoryBean(ApplicationContext applicationContext) {

 SchedulerFactoryBean factory = new SchedulerFactoryBean();

 factory.setOverwriteExistingJobs(true);
 factory.setJobFactory(jobFactory(applicationContext));

 Properties quartzProperties = new Properties();
 quartzProperties.setProperty("org.quartz.scheduler.instanceName",instanceName);
 quartzProperties.setProperty("org.quartz.scheduler.instanceId",instanceId);
 quartzProperties.setProperty("org.quartz.threadPool.threadCount",threadCount);

 factory.setDataSource(dataSource);

 factory.setQuartzProperties(quartzProperties);
 factory.setTriggers(emailJobTrigger().getObject());

 return factory;
 }

 @Bean(name = "emailJobTrigger")
 public SimpleTriggerFactoryBean emailJobTrigger() {


 SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
 factoryBean.setJobDetail(emailJobDetails().getObject());
 factoryBean.setStartDelay(startDelay);
 factoryBean.setRepeatInterval(repeatInterval);
 factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
 factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT);
 return factoryBean;
 }

 @Bean(name = "emailJobDetails")
 public JobDetailFactoryBean emailJobDetails() {

 JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
 jobDetailFactoryBean.setJobClass(EmailJob.class);
 jobDetailFactoryBean.setDescription(description);
 jobDetailFactoryBean.setDurability(true);
 jobDetailFactoryBean.setName(key);

 return jobDetailFactoryBean;
 }
}

What we did is creating a scheduler factory bean using the QuartzJobFactory we defined and we registered the triggers needed for our jobs to run. In our case we implemented a simple trigger running every minute.

You can find the source code on github

Reference: Integrating Quartz with Spring from our JCG partner Emmanouil Gkatziouras at the gkatzioura blog.
Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Thank you!

We will contact you soon.

πŸ‘ Photo of Emmanouil Gkatziouras
Emmanouil Gkatziouras
June 12th, 2016Last Updated: June 10th, 2016
0 198 3 minutes read

Emmanouil Gkatziouras

He is a versatile software engineer with experience in a wide variety of applications/services.He is enthusiastic about new projects, embracing new technologies, and getting to know people in the field of software.
Subscribe

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button
Close
wpDiscuz