SpringBoot officially supports the task scheduling framework, and it is also very delicious to be lightweight!

Earlier we talked about a distributed task scheduling framework PowerJob, which can perform task scheduling in a visual way. But sometimes we just need a lightweight task scheduling function, and it is a bit heavy for PowerJob to build a scheduling center. At this time, Quartz, the task scheduling framework officially supported by SpringBoot, comes in handy! This article mainly introduces the use of Quartz in SpringBoot, giving you more choices in implementing task scheduling!

SpringBoot actual e-commerce project mall (40k+star) address: https://github.com/macrozheng/mall

About Quartz

Quartz is a powerful open source task scheduling framework that can be integrated into almost any Java application (from a small stand-alone application to a large distributed application). Quartz can be used to create simple or complex task schedules to execute tens of thousands of tasks. Tasks are defined as standardized Java components, and tasks written in Java can be executed.

core concept

There are some core concepts in Quartz, and understanding them is very helpful for using Quartz!

  • Scheduler: The task scheduler in Quartz, which can be used to schedule, suspend and delete tasks through Trigger and JobDetail.
  • Trigger: Trigger in Quartz, you can specify the time of task execution through CRON expression, and the task execution will be automatically triggered when the time is up.
  • JobDetail (task details): The details of the tasks to be executed in Quartz, including the unique identifier of the task and the specific task to be executed. Data can be passed to the task through JobDataMap.
  • Job (task): A specific task in Quartz, including the specific method of executing the task.

CRON expression

Cron expression is a string, including 6~7 time elements, which can be used to specify the execution time of the task in Quartz.

Syntax of CRON

Seconds Minutes Hours DayofMonth Month DayofWeek

Description of each time element in CRON format

time element characters that can appear valid value range
Seconds , - * / 0-59
Minutes , - * / 0-59
Hours , - * / 0-23
DayofMonth , - * / ? L W 0-31
Month , - * / 1-12
DayofWeek , - * / ? L # 1-7 or SUN-SAT

Description of special characters in CRON format

character effect Example
, List enumeration values Use 5, 10 in the Minutes field, which means that it is triggered once at 5 minutes and 10 minutes each
\- Indicates the trigger range Use 5-10 in the Minutes field to trigger every minute from 5 to 10 minutes
\* matches any value Use * in the Minutes field to indicate that it will be triggered every minute
/ The start time starts to trigger, and it is triggered every fixed time Use 5/10 in the Minutes field, which means that it is triggered once every 5 minutes and every 10 minutes.
? In DayofMonth and DayofWeek, for matching arbitrary values Use ? in the DayofMonth field to indicate that it is triggered once a day
\# In DayofMonth, determine the day of the week 1#3 means the third Sunday
L means last Use 5L in DayofWeek for triggering on the last Thursday
W Indicates valid working days (Monday to Friday) Use 5W on DayofMonth, if the 5th is a Saturday, it will trigger once on the 4th of the nearest weekday

Online CRON Expression Generator

In fact, there is no need to memorize the CRON expression. When you need to use it, you can directly use the online generator. The address: https://cron.qqe2.com/

Integrate SpringBoot usage

Next, let's talk about how to use Quartz in SpringBoot to achieve task scheduling. In the e-commerce system, there is often a need to send emails or in-site messages regularly. Let's take this as a scenario to realize it!

  • There are two ways to store task information in Quartz, using memory or using database to store, here we use the database storage method, first of all, we need to create a new Quartz related table, the table creation script is in the resources directory of the project, named tables_mysql.sql, create After success, there are 11 more tables in the database;

  • Next, add the relevant dependencies of Quartz in pom.xml, and SpringBoot officially has provided us with the relevant Starter;
<!--SpringBoot integrated QuartZ-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
  • Add Quartz related configuration in application.yml, just look at the comments for configuration instructions, mainly to configure scheduler, jobStore and threadPool;
spring:
  quartz:
    job-store-type: jdbc # quartz task storage type: jdbc or memory
    wait-for-jobs-to-complete-on-shutdown: true # Wait for task to complete on shutdown
    overwrite-existing-jobs: true # Can overwrite existing tasks
    properties: # quartz native configuration
      org:
        quartz:
          scheduler:
            instanceName: scheduler # Scheduler instance name
            instanceId: AUTO # Scheduler instance ID is automatically generated
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX # Schedule information storage processing class
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate # Use a fully JDBC-compliant driver
            tablePrefix: QRTZ_ # quartz related table prefix
            useProperties: false # Whether to convert attributes in JobDataMap to string storage
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool # Specify the thread pool implementation class to provide a fixed size thread pool to the scheduler
            threadCount: 10 # Set the number of concurrent threads
            threadPriority: 5 # Specify thread priority
  • Create a task scheduling business interface, and define three methods, namely scheduling tasks through CRON expressions, scheduling tasks at specified time, and canceling timed tasks;
/**
 * Quartz Scheduled task operation class
 * Created by macro on 2020/9/27.
 */
public interface ScheduleService {
    /**
     * Scheduling tasks via CRON expressions
     */
    String scheduleJob(Class<? extends Job> jobBeanClass, String cron, String data);

    /**
     * Schedule a task at a specified time
     */
    String scheduleFixTimeJob(Class<? extends Job> jobBeanClass, Date startTime, String data);

    /**
     * Cancel a scheduled task
     */
    Boolean cancelScheduleJob(String jobName);
}
  • Create task scheduling business implementation classes, and implement related methods through Scheduler, CronTrigger, and JobDetail API s;
/**
 * Quartz Scheduled task operation implementation class
 * Created by macro on 2020/9/27.
 */
@Slf4j
@Service
public class ScheduleServiceImpl implements ScheduleService {
    @Autowired
    private Scheduler scheduler;
    private String defaultGroup = "default_group";

    @Override
    public String scheduleJob(Class<? extends Job> jobBeanClass, String cron, String data) {
        // Create tasks that need to be performed
        String jobName = UUID.fastUUID().toString();
        JobDetail jobDetail = JobBuilder.newJob(jobBeanClass)
                .withIdentity(jobName, defaultGroup)
                .usingJobData("data", data)
                .build();
        //Create a trigger to specify the task execution time
        CronTrigger cronTrigger = TriggerBuilder.newTrigger()
                .withIdentity(jobName, defaultGroup)
                .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                .build();
        //Task scheduling using the scheduler
        try {
            scheduler.scheduleJob(jobDetail, cronTrigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.info("Failed to create scheduled task!");
        }
        return jobName;
    }

    @Override
    public String scheduleFixTimeJob(Class<? extends Job> jobBeanClass, Date startTime, String data) {
        //Date to CRON Expression
        String startCron = String.format("%d %d %d %d %d ? %d",
                DateUtil.second(startTime),
                DateUtil.minute(startTime),
                DateUtil.hour(startTime, true),
                DateUtil.dayOfMonth(startTime),
                DateUtil.month(startTime) + 1,
                DateUtil.year(startTime));
        return scheduleJob(jobBeanClass, startCron, data);
    }

    @Override
    public Boolean cancelScheduleJob(String jobName) {
        boolean success = false;
        try {
            // Pause trigger
            scheduler.pauseTrigger(new TriggerKey(jobName, defaultGroup));
            // Remove tasks from triggers
            scheduler.unscheduleJob(new TriggerKey(jobName, defaultGroup));
            // delete task
            scheduler.deleteJob(new JobKey(jobName, defaultGroup));
            success = true;
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return success;
    }
}
  • Define the tasks that need to be executed, inherit the QuartzJobBean class, and implement the executeInternal method. Three tasks are defined here, sending emails regularly, sending internal messages regularly, and executing CRON expression tasks;
/**
 * Send Email Scheduled Task Executor
 * Created by macro on 2020/9/27.
 */
@Slf4j
@Component
public class SendEmailJob extends QuartzJobBean {
    @Autowired
    private ScheduleService scheduleService;

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        Trigger trigger = jobExecutionContext.getTrigger();
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        String data = jobDataMap.getString("data");
        log.info("Scheduled sending email operations:{}",data);
        //Delete triggers and tasks when done
        scheduleService.cancelScheduleJob(trigger.getKey().getName());
    }
}
/**
 * Timed task executor for sending intra-station messages
 * Created by macro on 2020/9/27.
 */
@Slf4j
@Component
public class SendMessageJob extends QuartzJobBean {
    @Autowired
    private ScheduleService scheduleService;

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        Trigger trigger = jobExecutionContext.getTrigger();
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        String data = jobDataMap.getString("data");
        log.info("The operation of sending intra-station messages regularly:{}",data);
        //Delete triggers and tasks when done
        scheduleService.cancelScheduleJob(trigger.getKey().getName());
    }
}
/**
 * Task executor using CRON expressions
 * Created by macro on 2020/9/29.
 */
@Slf4j
@Component
public class CronProcessJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        String data = jobDataMap.getString("data");
        log.info("CRON Expression task execution:{}",data);
    }
}
  • Finally, create a task scheduling related interface and call the task scheduling business class.
/**
 * Scheduled Task Scheduling Related Interfaces
 * Created by macro on 2020/9/29.
 */
@Api(tags = "ScheduleController", description = "Scheduled Task Scheduling Related Interfaces")
@RestController
@RequestMapping("/schedule")
public class ScheduleController {
    @Autowired
    private ScheduleService scheduleService;

    @ApiOperation("Send emails regularly")
    @PostMapping("/sendEmail")
    public CommonResult sendEmail(@RequestParam String startTime,@RequestParam String data) {
        Date date = DateUtil.parse(startTime, DatePattern.NORM_DATETIME_FORMAT);
        String jobName = scheduleService.scheduleFixTimeJob(SendEmailJob.class, date, data);
        return CommonResult.success(jobName);
    }

    @ApiOperation("Send intra-station messages regularly")
    @PostMapping("/sendMessage")
    public CommonResult sendMessage(@RequestParam String startTime,@RequestParam String data) {
        Date date = DateUtil.parse(startTime, DatePattern.NORM_DATETIME_FORMAT);
        String jobName = scheduleService.scheduleFixTimeJob(SendMessageJob.class, date, data);
        return CommonResult.success(jobName);
    }

    @ApiOperation("pass CRON Expression scheduling tasks")
    @PostMapping("/scheduleJob")
    public CommonResult scheduleJob(@RequestParam String cron, @RequestParam String data) {
        String jobName = scheduleService.scheduleJob(CronProcessJob.class, cron, data);
        return CommonResult.success(jobName);
    }

    @ApiOperation("Cancel a scheduled task")
    @PostMapping("/cancelScheduleJob")
    public CommonResult cancelScheduleJob(@RequestParam String jobName) {
        Boolean success = scheduleService.cancelScheduleJob(jobName);
        return CommonResult.success(success);
    }
}

run the test

  • Call the interface test to send email regularly;

  • After reaching the point, it is found that the console has printed the task execution information;
2020-09-30 11:23:00.035  INFO 10160 --- [eduler_Worker-1] com.macro.mall.tiny.job.SendEmailJob     : Timing send email operation: send email content
  • Use the CRON expression to start a scheduled task, starting from 0s and executing it every 10s;

  • The console prints task execution information every 10s;
2020-09-30 11:26:30.024  INFO 10160 --- [eduler_Worker-2] com.macro.mall.tiny.job.CronProcessJob   : CRON Expression task execution: CRON Message content
2020-09-30 11:26:40.025  INFO 10160 --- [eduler_Worker-3] com.macro.mall.tiny.job.CronProcessJob   : CRON Expression task execution: CRON Message content
2020-09-30 11:26:50.017  INFO 10160 --- [eduler_Worker-4] com.macro.mall.tiny.job.CronProcessJob   : CRON Expression task execution: CRON Message content
2020-09-30 11:27:00.023  INFO 10160 --- [eduler_Worker-5] com.macro.mall.tiny.job.CronProcessJob   : CRON Expression task execution: CRON Message content
2020-09-30 11:27:10.019  INFO 10160 --- [eduler_Worker-6] com.macro.mall.tiny.job.CronProcessJob   : CRON Expression task execution: CRON Message content
  • We can cancel the task by calling the jobName returned by the start task and calling the interface for canceling the scheduled task. After the call is successful, the scheduled task will not be executed.

References

Official documentation: http://www.quartz-scheduler.o...

Project source code address

https://github.com/macrozheng...

This article GitHub https://github.com/macrozheng/mall-learning It has been recorded, welcome everyone to Star!

Tags: Java Spring Boot Back-end

Posted by dpiland on Sat, 07 May 2022 07:51:28 +0300