Spring @Scheduled vs Quartz Scheduler Example
1. Introduction
Spring is a Java application framework that provides many useful services for building applications. It provides two annotations to enable scheduling tasks:
@EnableScheduling– to enable Spring’s scheduled task execution capability. It’s used on a class with@Configurationannotation.@Scheduled– to mark a method to be scheduled. The annotated method must have no arguments and avoidreturn type.
Quartz is an open source library designed to schedule a job for enterprises. It provides several interfaces and classes to schedule a job:
org.quartz.Jobinterface – any class which implements it can be used to schedule a job.org.quartz.ScheduleBuilder– abstract class to construct scheduling-related entities. There are four sub-classes:CalendarIntervalScheduleBuilder,CronScheduleBuilder,DailyTimeIntervalScheduleBuilder, andSimpleScheduleBuilder.org.quartz.SchedulerFactoryinterface –DirectSchedulerFactoryandStdSchedulerFactoryimplement it to schedule a job.
In this example, I will build two scheduler applications: one with Spring, the other with Quartz.
2. Technologies used
The example code in this article was built and run using:
- Java 1.8.101
- Maven 3.3.9
- Quartz 2.3.0
- Spring Boot 2.1.2.RELEASE
- Eclipse Oxygen
- Logback 1.2.3
3. Maven Project
Spring Boot Starters provides more than 30 starters to ease the dependency management for your projects. I will use it to generate a Spring Boot application:
- Go to
https://start.spring.io/. - Select
Maven ProjectwithJavaand Spring Boot version. - Enter the group name:
jcg.zheng.demoand artifact:quartz-spring-demo. - Click the
Generate Projectbutton.
A maven project will be generated and downloaded to your workstation. Import it into your Eclipse workspace.
3.1 Pom.xml
Add dependencies to the pom.xml.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jcg.zheng.demo</groupId> <artifactId>quartz-spring-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>quartz-spring-demo</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.2.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
3.2 Business Task
In this step, I will create a BusinessTask.java class whose method takes 90 seconds to complete and throw a RuntimeException when the current thread’s name ends with “2”.
BusinessTask.java
package jcg.zheng.demo.scheduler.spring.service;
import org.springframework.stereotype.Service;
@Service
public class BusinessTask {
private static final long NITY_SECONDS = 90000;
public void doit() {
if (Thread.currentThread().getName().endsWith("2")) {
throw new RuntimeException("Opps! unexpected Error!");
}
try {
Thread.sleep(NITY_SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.3 Application Properties
In this step, I will create an application.properties to hold the cron expression string and fixed rate value in milliseconds.
application.properties
scheduler.cron.expression=0 * * * * ? scheduler.fixedrate.ms=15000
3.4 Logback.xml
To illustrate the scheduled job, I will configure a logback.xml file for each scheduler.
logback.xml
<configuration debug="true" scan="true"
scanPeriod="150 seconds">
<property name="LOG_DIR" value="logs" />
<appender name="CONSOLE"
class="ch.qos.logback.core.ConsoleAppender" target="System.out">
<encoder>
<charset>UTF-8</charset>
<Pattern>%d %-4relative [%thread] %-5level %logger{35} - %msg%n
</Pattern>
</encoder>
</appender>
<appender name="SPRING_SCHEDULER_FILE_FIXEDRATE"
class="ch.qos.logback.core.FileAppender">
<file>${LOG_DIR}/spring_scheduler_fixedRate.log</file>
<encoder>
<charset>UTF-8</charset>
<Pattern>%d %-4relative [%thread] %-5level %logger{35} - %msg%n
</Pattern>
</encoder>
</appender>
<appender name="SPRING_SCHEDULER_FILE_FIXEDRATE_ASYNC"
class="ch.qos.logback.core.FileAppender">
<file>${LOG_DIR}/spring_scheduler_fixedRate_async.log</file>
<encoder>
<charset>UTF-8</charset>
<Pattern>%d %-4relative [%thread] %-5level %logger{35} - %msg%n
</Pattern>
</encoder>
</appender>
<appender name="SPRING_SCHEDULER_FILE_FIXEDDELAY"
class="ch.qos.logback.core.FileAppender">
<file>${LOG_DIR}/spring_scheduler_fixedDelay.log</file>
<encoder>
<charset>UTF-8</charset>
<Pattern>%d %-4relative [%thread] %-5level %logger{35} - %msg%n
</Pattern>
</encoder>
</appender>
<appender name="SPRING_SCHEDULER_FILE_FIXEDDELAY_ASYNC"
class="ch.qos.logback.core.FileAppender">
<file>${LOG_DIR}/spring_scheduler_fixedDelay_async.log</file>
<encoder>
<charset>UTF-8</charset>
<Pattern>%d %-4relative [%thread] %-5level %logger{35} - %msg%n
</Pattern>
</encoder>
</appender>
<appender name="SPRING_SCHEDULER_FILE_CRON"
class="ch.qos.logback.core.FileAppender">
<file>${LOG_DIR}/spring_scheduler_cron.log</file>
<encoder>
<charset>UTF-8</charset>
<Pattern>%d %-4relative [%thread] %-5level %logger{35} - %msg%n
</Pattern>
</encoder>
</appender>
<appender name="SPRING_SCHEDULER_FILE_CRON_ASYNC"
class="ch.qos.logback.core.FileAppender">
<file>${LOG_DIR}/spring_scheduler_cron_async.log</file>
<encoder>
<charset>UTF-8</charset>
<Pattern>%d %-4relative [%thread] %-5level %logger{35} - %msg%n
</Pattern>
</encoder>
</appender>
<appender name="QUARTZ_SCHEDULER_FILE"
class="ch.qos.logback.core.FileAppender">
<file>${LOG_DIR}/quartz_scheduler.log</file>
<encoder>
<charset>UTF-8</charset>
<Pattern>%d %-4relative [%thread] %-5level %logger{35} - %msg%n
</Pattern>
</encoder>
</appender>
<logger name="jcg.zheng.demo.scheduler.quartz" level="info"
additivity="false">
<appender-ref ref="QUARTZ_SCHEDULER_FILE" />
</logger>
<logger
name="jcg.zheng.demo.scheduler.spring.scheduler.FixedRateScheduler_HandleException"
level="info" additivity="false">
<appender-ref ref="SPRING_SCHEDULER_FILE_FIXEDRATE" />
</logger>
<logger
name="jcg.zheng.demo.scheduler.spring.scheduler.AsyncFixedRateScheduler"
level="info" additivity="false">
<appender-ref ref="SPRING_SCHEDULER_FILE_FIXEDRATE_ASYNC" />
</logger>
<logger
name="jcg.zheng.demo.scheduler.spring.scheduler.FixedDelayScheduler"
level="info" additivity="false">
<appender-ref ref="SPRING_SCHEDULER_FILE_FIXEDDELAY" />
</logger>
<logger
name="jcg.zheng.demo.scheduler.spring.scheduler.AsyncFixedDelayScheduler"
level="info" additivity="false">
<appender-ref
ref="SPRING_SCHEDULER_FILE_FIXEDDELAY_ASYNC" />
</logger>
<logger
name="jcg.zheng.demo.scheduler.spring.scheduler.CronScheduler"
level="info" additivity="false">
<appender-ref ref="SPRING_SCHEDULER_FILE_CRON" />
</logger>
<logger
name="jcg.zheng.demo.scheduler.spring.scheduler.AsyncCronScheduler"
level="info" additivity="false">
<appender-ref ref="SPRING_SCHEDULER_FILE_CRON_ASYNC" />
</logger>
<root level="info">
<appender-ref ref="CONSOLE" />
</root>
</configuration>4. Quartz Scheduler
In this step, I will create a Quartz scheduler application. It will schedule two jobs:
- One runs every minute triggered by a
cronexpression. - Another runs with one minute intervals for a total of 30 times.
4.1 QuartzJob
Quartz job must implement org.quartz.Job interface. In this step, I will create a QuartzJob class which implements org.quartz.Jobinterface and overrides the execute method.
QuartzJob.java
package jcg.zheng.demo.scheduler.quartz;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jcg.zheng.demo.scheduler.spring.service.BusinessTask;
public class QuartzJob implements Job {
Logger logger = LoggerFactory.getLogger(QuartzJob.class);
private BusinessTask service = new BusinessTask();
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
logger.info(" started ");
service.doit();
logger.info(" completed.");
}
}
I will create QuartzJob_HandleException.java which does same as above class with additional exception handling logic.
QuartzJob_HandleException.java
package jcg.zheng.demo.scheduler.quartz;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jcg.zheng.demo.scheduler.spring.service.BusinessTask;
public class QuartzJob_HandleException implements Job {
Logger logger = LoggerFactory.getLogger(QuartzJob_HandleException.class);
private BusinessTask service = new BusinessTask();
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
logger.info(" started ");
boolean isCompleted = false;
try {
service.doit();
isCompleted = true;
} catch (Exception e) {
logger.error("Failed. due to " + e.getMessage());
} finally {
logger.info(" completed with status=" + isCompleted);
}
}
}
4.2 Quartz Scheduler
Quartz library provides org.quartz.impl.StdSchedulerFactory. I will use it to create a scheduler instance and schedule two jobs: one for QuartzJob_HandleException with CronScheduleBuilder, the other for QuartzJob with SimpleScheduleBuilder.
QuartzScheduler.java
package jcg.zheng.demo.scheduler.quartz;
import org.quartz.CronScheduleBuilder;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class QuartzScheduler {
static Logger logger = LoggerFactory.getLogger(QuartzScheduler.class);
private static final String TRIGGER_NAME = "MyTriggerName";
private static final String JOB_NAME = "someJob";
private static final String CRON_EXPRESSION_EVERY_SECOND_1 = "1 * * * * ?";
private Scheduler scheduler;
public void start() throws Exception {
logger.info("QuartzScheduler started. ");
scheduler = new StdSchedulerFactory().getScheduler();
scheduleJob(buildCronSchedulerTrigger("cronGroup"), QuartzJob_HandleException.class, "cronGroup");
scheduleJob(buildSimpleSchedulerTrigger("simpleGroup"), QuartzJob.class, "simpleGroup");
scheduler.start();
}
private void scheduleJob(Trigger trigger, Class jobClass, String groupName) throws Exception {
JobDetail someJobDetail = JobBuilder.newJob(jobClass).withIdentity(JOB_NAME, groupName).build();
scheduler.scheduleJob(someJobDetail, trigger);
}
private Trigger buildCronSchedulerTrigger(String groupName) {
return TriggerBuilder
.newTrigger().withIdentity(TRIGGER_NAME, groupName).withSchedule(CronScheduleBuilder
.cronSchedule(CRON_EXPRESSION_EVERY_SECOND_1).withMisfireHandlingInstructionDoNothing())
.build();
}
private Trigger buildSimpleSchedulerTrigger(String groupName) {
return TriggerBuilder
.newTrigger().withIdentity(TRIGGER_NAME, groupName).withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withRepeatCount(30).withIntervalInMinutes(1).withMisfireHandlingInstructionIgnoreMisfires())
.build();
}
}
4.3 Demo
In this step, I will create a java application to start the Quartz scheduler application.
Note: Quartz provides ten threads as the default thread pool count.
QuartzSchedulerApplication.java
package jcg.zheng.demo.scheduler.quartz;
public class QuartzSchedulerApplication {
public static void main(String[] args) throws Exception {
QuartzScheduler scheduler = new QuartzScheduler();
scheduler.start();
}
}
Quartz log
2019-01-23 14:00:06,336 234 [main] INFO j.z.d.s.quartz.QuartzScheduler - QuartzScheduler started. 2019-01-23 14:00:06,431 329 [DefaultQuartzScheduler_Worker-1] INFO j.z.demo.scheduler.quartz.QuartzJob - started 2019-01-23 14:01:01,011 54909 [DefaultQuartzScheduler_Worker-2] INFO j.z.d.s.q.QuartzJob_HandleException - started 2019-01-23 14:01:01,011 54909 [DefaultQuartzScheduler_Worker-2] ERROR j.z.d.s.q.QuartzJob_HandleException - Failed. due to Opps! unexpected Error! 2019-01-23 14:01:01,011 54909 [DefaultQuartzScheduler_Worker-2] INFO j.z.d.s.q.QuartzJob_HandleException - completed with status=false 2019-01-23 14:01:06,436 60334 [DefaultQuartzScheduler_Worker-3] INFO j.z.demo.scheduler.quartz.QuartzJob - started 2019-01-23 14:01:36,427 90325 [DefaultQuartzScheduler_Worker-1] INFO j.z.demo.scheduler.quartz.QuartzJob - completed. 2019-01-23 14:02:01,004 114902 [DefaultQuartzScheduler_Worker-4] INFO j.z.d.s.q.QuartzJob_HandleException - started 2019-01-23 14:02:06,428 120326 [DefaultQuartzScheduler_Worker-5] INFO j.z.demo.scheduler.quartz.QuartzJob - started 2019-01-23 14:02:36,477 150375 [DefaultQuartzScheduler_Worker-3] INFO j.z.demo.scheduler.quartz.QuartzJob - completed. 2019-01-23 14:03:01,007 174905 [DefaultQuartzScheduler_Worker-6] INFO j.z.d.s.q.QuartzJob_HandleException - started 2019-01-23 14:03:06,473 180371 [DefaultQuartzScheduler_Worker-7] INFO j.z.demo.scheduler.quartz.QuartzJob - started 2019-01-23 14:03:31,009 204907 [DefaultQuartzScheduler_Worker-4] INFO j.z.d.s.q.QuartzJob_HandleException - completed with status=true 2019-01-23 14:03:36,433 210331 [DefaultQuartzScheduler_Worker-5] INFO j.z.demo.scheduler.quartz.QuartzJob - completed. 2019-01-23 14:04:01,029 234927 [DefaultQuartzScheduler_Worker-8] INFO j.z.d.s.q.QuartzJob_HandleException - started 2019-01-23 14:04:06,430 240328 [DefaultQuartzScheduler_Worker-9] INFO j.z.demo.scheduler.quartz.QuartzJob - started 2019-01-23 14:04:31,013 264911 [DefaultQuartzScheduler_Worker-6] INFO j.z.d.s.q.QuartzJob_HandleException - completed with status=true 2019-01-23 14:04:36,444 270342 [DefaultQuartzScheduler_Worker-7] INFO j.z.demo.scheduler.quartz.QuartzJob - completed. 2019-01-23 14:05:01,010 294908 [DefaultQuartzScheduler_Worker-10] INFO j.z.d.s.q.QuartzJob_HandleException - started 2019-01-23 14:05:06,434 300332 [DefaultQuartzScheduler_Worker-2] INFO j.z.demo.scheduler.quartz.QuartzJob - started
5. Spring Scheduler
In this step, I will create a Spring boot application which enables the scheduling and has several schedulers.
5.1 Scheduler Configuration
Spring provides a single thread as the default setting for all the tasks marked with @Scheduled annotation. You don’t need this step if a single thread scheduler meets your requirements.
Spring framework provides TaskScheduler interface and its own implementation, such as ThreadPoolTaskScheduler. It also provides a SchedulingConfigurer functional interface which sets up a specified task scheduler.
In this step, I will configure a four-thread pool with ThreadPoolTaskScheduler and mark it with @EnableAsync.
SchedulerConfig.java
package jcg.zheng.demo.scheduler.spring;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
@Configuration
@EnableAsync
public class SchedulerConfig implements SchedulingConfigurer {
Logger logger = LoggerFactory.getLogger(SchedulerConfig.class);
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegister) {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setErrorHandler(t-> logger.error("Caught exception on the @Scheduled task. " + t.getMessage()));
taskScheduler.setPoolSize(4);
taskScheduler.setThreadNamePrefix("Spring-scheduler-task-pool-");
taskScheduler.initialize();
scheduledTaskRegister.setTaskScheduler(taskScheduler);
}
}
5.2 Spring boot application
I will add @EnableScheduling annotation to the generated SpringSchedulerApplication.java.
SpringSchedulerApplication.java
package jcg.zheng.demo.scheduler.spring;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class SpringSchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSchedulerApplication.class, args);
}
}
5.3 Fixed Rate Scheduler
Spring @Scheduled annotation has fixedRate and fixedRateString attributes. Tasks with this attribute are executed in a fixed interval in milliseconds. fixedRate requires an integer value and fixedRateString requires a String value.
In this step, I will create two schedulers for the fixedRate attributes: one with an exception handling, the other with @Async annotation.
FixedRateScheduler_HandleException.java
package jcg.zheng.demo.scheduler.spring.scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import jcg.zheng.demo.scheduler.spring.service.BusinessTask;
@Component
public class FixedRateScheduler_HandleException {
@Autowired
private BusinessTask service;
Logger logger = LoggerFactory.getLogger(FixedRateScheduler_HandleException.class);
// will wait for previous execution because it's not marked as Async
@Scheduled(fixedRateString = "${scheduler.fixedrate.ms}")
public void scheduledTask() {
logger.info(" started.");
boolean isCompleted = false;
try {
service.doit();
isCompleted = true;
} catch (Exception e) {
logger.error("Caught Exception" + e.getMessage());
} finally {
logger.info(" completed with status=" + isCompleted);
}
}
}
AsyncFixedRateScheduler.java
package jcg.zheng.demo.scheduler.spring.scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import jcg.zheng.demo.scheduler.spring.service.BusinessTask;
@Component
public class AsyncFixedRateScheduler {
@Autowired
private BusinessTask service;
Logger logger = LoggerFactory.getLogger(AsyncFixedRateScheduler.class);
// trigger with every 15 seconds, will not wait for the previous execution
@Scheduled(fixedRate = 15000)
@Async
public void scheduledTask() {
logger.info(" started.");
service.doit();
logger.info(" completed.");
}
}
5.4 Fixed Delay Scheduler
Spring @Scheduled annotation has fixedDelay and fixedDelayString attributes. Tasks with this attribute are executed sequentially and the next execution is waited for the previous execution with a fixed delay in milliseconds. fixedDelay requires an Integer value and fixedDelayString requires a String value.
FixedDelayScheduler.java
package jcg.zheng.demo.scheduler.spring.scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import jcg.zheng.demo.scheduler.spring.service.BusinessTask;
@Component
public class FixedDelayScheduler {
@Autowired
private BusinessTask service;
Logger logger = LoggerFactory.getLogger(FixedDelayScheduler.class);
// trigger by delay 15 seconds after previous execution, the intial execution is
// delayed by 30 seconds
@Scheduled(fixedDelay = 15000, initialDelay = 30000)
public void scheduledTask() {
logger.info(" started.");
service.doit();
logger.info(" completed.");
}
}
AsyncFixedDelayScheduler.java
package jcg.zheng.demo.scheduler.spring.scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import jcg.zheng.demo.scheduler.spring.service.BusinessTask;
@Component
public class AsyncFixedDelayScheduler {
@Autowired
private BusinessTask service;
Logger logger = LoggerFactory.getLogger(AsyncFixedDelayScheduler.class);
// trigger by delay 15 seconds after previous execution, the intial execution is
// delayed by 30 seconds
@Scheduled(fixedDelay = 15000, initialDelay = 30000)
@Async
public void scheduleFixedDelayTask() {
logger.info(" started.");
service.doit();
logger.info(" completed.");
}
}
5.5 Cron Scheduler
Spring @Scheduled annotation has a cron attribute. Tasks with this attribute are executed based on a cron expression.
Note: it always waits for the previous execution.
CronScheduler.java
package jcg.zheng.demo.scheduler.spring.scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import jcg.zheng.demo.scheduler.spring.service.BusinessTask;
@Component
public class CronScheduler {
@Autowired
private BusinessTask service;
Logger logger = LoggerFactory.getLogger(CronScheduler.class);
@Scheduled(cron = "${scheduler.cron.expression}")
public void schedulesTask() {
logger.info(" started.");
service.doit();
logger.info(" completed.");
}
}
AsyncCronScheduler.java
package jcg.zheng.demo.scheduler.spring.scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import jcg.zheng.demo.scheduler.spring.service.BusinessTask;
@Component
public class CronScheduler {
@Autowired
private BusinessTask service;
Logger logger = LoggerFactory.getLogger(CronScheduler.class);
@Scheduled(cron = "${scheduler.cron.expression}")
public void schedulesTask() {
logger.info(" started.");
service.doit();
logger.info(" completed.");
}
}
5.6 Demo
Execute it as a Spring boot application and check the log files. I will only list the fixed_rate_scheduler log as an example.
Fixed_Rate_scheduler log
2019-01-23 14:12:38,601 1666 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 14:12:38,602 1667 [Spring-scheduler-task-pool-2] ERROR j.z.d.s.s.s.FixedRateScheduler_HandleException - Caught ExceptionOpps! unexpected Error! 2019-01-23 14:12:38,602 1667 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - completed with status=false 2019-01-23 14:12:53,603 16668 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 14:12:53,604 16669 [Spring-scheduler-task-pool-2] ERROR j.z.d.s.s.s.FixedRateScheduler_HandleException - Caught ExceptionOpps! unexpected Error! 2019-01-23 14:12:53,604 16669 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - completed with status=false 2019-01-23 14:13:08,632 31697 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 14:13:08,632 31697 [Spring-scheduler-task-pool-2] ERROR j.z.d.s.s.s.FixedRateScheduler_HandleException - Caught ExceptionOpps! unexpected Error! 2019-01-23 14:13:08,632 31697 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - completed with status=false 2019-01-23 14:13:23,629 46694 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 14:13:23,629 46694 [Spring-scheduler-task-pool-2] ERROR j.z.d.s.s.s.FixedRateScheduler_HandleException - Caught ExceptionOpps! unexpected Error! 2019-01-23 14:13:23,629 46694 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - completed with status=false 2019-01-23 14:13:38,637 61702 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 14:13:38,640 61705 [Spring-scheduler-task-pool-2] ERROR j.z.d.s.s.s.FixedRateScheduler_HandleException - Caught ExceptionOpps! unexpected Error! 2019-01-23 14:13:38,640 61705 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - completed with status=false 2019-01-23 14:13:53,640 76705 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 14:13:53,640 76705 [Spring-scheduler-task-pool-2] ERROR j.z.d.s.s.s.FixedRateScheduler_HandleException - Caught ExceptionOpps! unexpected Error! 2019-01-23 14:13:53,640 76705 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - completed with status=false 2019-01-23 14:14:08,642 91707 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 14:14:08,642 91707 [Spring-scheduler-task-pool-2] ERROR j.z.d.s.s.s.FixedRateScheduler_HandleException - Caught ExceptionOpps! unexpected Error! 2019-01-23 14:14:08,642 91707 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - completed with status=false 2019-01-23 14:14:23,636 106701 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 14:14:23,636 106701 [Spring-scheduler-task-pool-2] ERROR j.z.d.s.s.s.FixedRateScheduler_HandleException - Caught ExceptionOpps! unexpected Error! 2019-01-23 14:14:23,636 106701 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - completed with status=false 2019-01-23 14:14:38,643 121708 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 14:14:38,643 121708 [Spring-scheduler-task-pool-2] ERROR j.z.d.s.s.s.FixedRateScheduler_HandleException - Caught ExceptionOpps! unexpected Error! 2019-01-23 14:14:38,643 121708 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - completed with status=false 2019-01-23 14:14:53,607 136672 [Spring-scheduler-task-pool-1] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 14:16:23,616 226681 [Spring-scheduler-task-pool-1] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - completed with status=true 2019-01-23 14:16:23,616 226681 [Spring-scheduler-task-pool-1] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 14:17:53,654 316719 [Spring-scheduler-task-pool-1] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - completed with status=true 2019-01-23 14:17:53,654 316719 [Spring-scheduler-task-pool-1] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 19:12:37,885 1673 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 19:12:37,885 1673 [Spring-scheduler-task-pool-2] ERROR j.z.d.s.s.s.FixedRateScheduler_HandleException - Caught ExceptionOpps! unexpected Error! 2019-01-23 19:12:37,886 1674 [Spring-scheduler-task-pool-2] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - completed with status=false 2019-01-23 19:12:52,886 16674 [Spring-scheduler-task-pool-4] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 19:14:22,890 106678 [Spring-scheduler-task-pool-4] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - completed with status=true 2019-01-23 19:14:22,890 106678 [Spring-scheduler-task-pool-4] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started. 2019-01-23 19:15:52,894 196682 [Spring-scheduler-task-pool-4] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - completed with status=true 2019-01-23 19:15:52,894 196682 [Spring-scheduler-task-pool-4] INFO j.z.d.s.s.s.FixedRateScheduler_HandleException - started.
6. Spring @Scheduled vs Quartz Scheduler – Summary
There are three things we must do to use Quartz scheduler:
- Create a task class which implements the
org.quartz.Jobinterface - Create a trigger with
SimpleScheduleBuilder,CronScheduleBuilder,etc - Create a quartz scheduler instance from the Quartz factory class and schedule a job with a corresponding trigger.
There are only two things we must do to use Spring scheduler:
- Add
@EnableSchedulingannotation on a class with@Configurationannotation - Add
@Scheduledannotation for the scheduled method.
Spring scheduling annotations make Spring scheduler easier to use.
7. Download the Source Code
This example builds two java scheduler applications: one utilizes Quartz and the other uses spring built-in scheduler library.
You can download the full source code of this example here: Spring @Scheduled vs Quartz Example


