Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Spring Boot integrates Spring Scheduler and Quartz Scheduler

2025-03-26 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/03 Report--

This paper introduces the basic knowledge of Spring Boot integrating Spring Scheduler and Quartz Scheduler, uses ShedLock to solve Spring Scheduler multi-instance running conflicts, introduces Quartz ScheduleBuilder and Calendar, and introduces the method of dynamically creating Quartz Job.

GitHub source code

Spring Scheduler

Spring Framework provides a simple and easy-to-use Job scheduling framework, Spring Scheduler.

Example

In Spring Boot, it takes only two steps to enable Scheduler:

Enable Schedulingpackage org.itrunner.heroes.scheduling;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.annotation.EnableScheduling;@Configuration@EnableSchedulingpublic class ScheduleConfig {} to define Schedule method package org.itrunner.heroes.scheduling;import lombok.extern.slf4j.Slf4j;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component @ Component@Slf4jpublic class HelloSpring {@ Scheduled (cron = "0 * / 10 *") public void sayHello () {log.info ("HelloSpring Scheduler");}}

@ Scheduled supports three definition methods: cron, fixedDelay and fixedRate. The method must have no parameters and return a void type.

ShedLock

By default, Spring cannot synchronize the scheduler for multiple instances and instead executes jobs on each node at the same time. We can use shedlock-spring to solve this problem, ensuring that only one task is scheduled at the same time.

Net.javacrumbs.shedlock shedlock-spring 4.1.0 net.javacrumbs.shedlock shedlock-provider-jdbc-template 4.1.0

ShedLock is implemented using a database locking mechanism and currently supports DynamoDB, Hazelcast, Mongo, Redis, ZooKeeper, and any JDBC Driver. To use JDBC, add the following dependencies:

Net.javacrumbs.shedlock shedlock-provider-jdbc-template 4.1.0

Create a Shedlock Entity:

Package org.itrunner.heroes.domain;import lombok.Data;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;import java.time.LocalDateTime;@Entity@Table (name = "shedlock") @ Datapublic class Shedlock {@ Id @ Column (name = "name", length = 64) private String name; @ Column (name = "lock_until") private LocalDateTime lockUntil; @ Column (name = "locked_at") private LocalDateTime lockedAt @ Column (name = "locked_by") private String lockedBy;}

Enable ShedLock:

Package org.itrunner.heroes.scheduling;import net.javacrumbs.shedlock.core.LockProvider;import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.annotation.EnableScheduling;import javax.sql.DataSource;@Configuration@EnableScheduling@EnableSchedulerLock (defaultLockAtMostFor = "PT30S") public class ScheduleConfig {@ Bean public LockProvider lockProvider (DataSource dataSource) {return new JdbcTemplateLockProvider (dataSource) }} package org.itrunner.heroes.scheduling;import lombok.extern.slf4j.Slf4j;import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;@Component@Slf4jpublic class HelloSpring {@ Scheduled (cron = "0 * / 10 *") @ SchedulerLock (name = "helloSpringScheduler", lockAtLeastFor = "PT30S", lockAtMostFor = "PT3M") public void sayHello () {log.info ("HelloSpring Scheduler") }}

The shortest and longest time for lockAtLeastFor and lockAtMostFor to set lock are 30 seconds and 3 minutes, respectively.

Quartz Scheduler

Quartz Scheduler is a powerful task scheduling framework, and Quartz can be used when Spring Scheduler can not meet the requirements.

Integrated QuartzPOM dependency

You only need to introduce the dependency spring-boot-starter-quartz in the Spring Boot project:

Org.springframework.boot spring-boot-starter-quartz configuration Quartz

By default, memory JobStore is used, and the database should be configured in a production environment:

Spring: quartz: auto-startup: true job-store-type: jdbc jdbc: initialize-schema: always overwrite-existing-jobs: true properties: org.quartz.threadPool.threadCount: 5

The advanced properties of Quartz can be configured in spring.quartz.properties.

Define Quartz Jobpackage org.itrunner.heroes.scheduling;import lombok.extern.slf4j.Slf4j;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import org.springframework.scheduling.quartz.QuartzJobBean;@Slf4jpublic class HelloQuartz extends QuartzJobBean {@ Override protected void executeInternal (JobExecutionContext jobExecutionContext) throws JobExecutionException {log.info ("HelloQuartz Scheduler");} register Job

After integrating Quartz, a Scheduler is automatically configured. SchedulerFactoryBean is responsible for creating and configuring Quartz Scheduler and managing its lifecycle as part of Spring application context. Scheduler can be injected into other components.

All JobDetail, Calendar, and Trigger Bean are automatically associated with scheduler, and scheduler is automatically started when Spring Boot is initialized and closed when destroyed.

Statically register Job

If you only need to register Job statically at startup, you only need to declare Bean and do not need to access the scheduler instance itself in the program, as follows:

Package org.itrunner.heroes.scheduling;import org.itrunner.heroes.util.DateUtils;import org.quartz.*;import org.quartz.impl.calendar.HolidayCalendar;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import java.time.LocalDate;@Configurationpublic class QuartzConfig {private static final String CRON_EXPRESSION = "0 amp 5 *?"; private static final String GROUP = "iTRunner" @ Bean public Trigger helloJobTrigger (JobDetail helloJob) {CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule (CRON_EXPRESSION); return TriggerBuilder.newTrigger () .forJob (helloJob) .withidentity (getTriggerKey (helloJob.getKey () .withschedule (scheduleBuilder) .modifiedByCalendar ("holidayCalendar"). Build ();} @ Bean public JobDetail helloJob () {return JobBuilder.newJob (HelloQuartz.class) .withty (getJobKey (HelloQuartz.class)). StoreDurably (). Build () } @ Bean public Calendar holidayCalendar () {HolidayCalendar calendar = new HolidayCalendar (); LocalDate date = LocalDate.of (2020, 1,1); calendar.addExcludedDate (DateUtils.toDate (date)); return calendar;} private static JobKey getJobKey (Class cls) {return new JobKey (cls.getSimpleName (), GROUP);} private static TriggerKey getTriggerKey (JobKey jobKey) {return new TriggerKey (jobKey.getName (), GROUP) }} ScheduleBuilder

In the above example, we use CronScheduleBuilder,Quartz to also support SimpleScheduleBuilder, DailyTimeIntervalScheduleBuilder, and CalendarIntervalScheduleBuilder.

SimpleScheduleBuilder executes tasks at specified intervals in milliseconds, seconds, minutes, or hours; you can specify the total number of times the task is executed. DailyTimeIntervalScheduleBuilder executes tasks at specified intervals every day, in seconds, minutes or hours; you can specify the start and end time of each day; you can specify what day of the week to execute You can specify the total number of tasks executed per day. CalendarIntervalScheduleBuilder executes tasks at specified time intervals. CronScheduleBuilder can use Cron expressions to define task execution time for seconds, minutes, hours, days, weeks, months, and years. It also supports convenient methods such as dailyAtHourAndMinute (), atHourAndMinuteOnGivenDaysOfWeek (), weeklyOnDayAndHourAndMinute (), monthlyOnDayAndHourAndMinute (), and so on.

Cron-Expression

The Cron expression consists of six required fields and one optional field, separated by spaces.

Field NameAllowed ValuesAllowed Special Characters seconds 0-59,-* / minute 0-59,-* / hour 0-23,-* / day 1-31,-*? / L WY0-11 or JAN-DEC,-* / week 1-7 or SUN-SAT,-*? / L # (optional) empty or 1970-2199,-* / * can be used in all fields, for example, in the minute field? Allows applications in the day and week fields to specify "non-specific values", equivalent to placeholders-for the specified range, such as in the hour field, "10-12" means 10 minutes 11, 12, and specifies list values, such as in the week field, "MON,WED,FRI" represents Monday, Wednesday, Friday / specified step size, such as in the second field, "0p15" means 0prit 15, 300,45; "5gam15" means 5, 20, 35, 50. If you use * / x, it is equivalent to 0Unix. L is used only in the day and week fields, meaning "last". In the day field, such as January 31, non-leap year February 28; in the week field, it means 7 or "SAT". If there is a value before L, such as 6L, it indicates the last Friday of the month. W is used only in the day field, indicating the working day closest to the specified date (Monday to Friday), such as 15W, indicating the closest working day to the 15th of the month. Note that you cannot cross the month. LW combination, indicating the last working day of the month # is used for the week field only, indicating the number, such as "6: 3", indicating the third Friday of this month

Example:

0 0B 5 *? 100 pounds every 5 minutes 5 *? Every 5 minutes, 10 seconds are performed, such as 10:00:10, 10 WED,FRI 05 WED,FRI 30 30 10-13? * every Wednesday and Friday at 10, 10, 10, 10 and 13 every Wednesday and Friday at 30 8-9 5 Jing 20 *? 8:00, 8:30, 9:00 and 9:30Calendar on the 5th and 20th of each month

Calendar does not define the actual trigger time, but is used in conjunction with Trigger to exclude specific times.

AnnualCalendar excludes one or more days of the year

CronCalendar uses Cron expressions to define the time of exclusion, such as "* 0-7, 18-23? *", excluding 8 to 17:00 every day.

DailyCalendar excludes the specified time period of each day

HolidayCalendar excludes holidays and needs to specify the exact date

MonthlyCalendar excludes one or more days of the month

WeeklyCalendar excludes one or more days of the week. Saturday and Sunday are excluded by default.

Dynamic Job

In many cases, we need to dynamically create or start and stop Job, such as Job data is dynamic, there is a dependency between Job, start and stop Job according to conditions, and so on.

The following example simply demonstrates the method of dynamically creating Job, adding calendar, adding listener, and starting and stopping job:

Package org.itrunner.heroes.scheduling;import lombok.extern.slf4j.Slf4j;import org.quartz.*;import org.quartz.impl.calendar.WeeklyCalendar;import org.quartz.impl.matchers.GroupMatcher;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import static org.itrunner.heroes.scheduling.Constants.*;@Service@Slf4jpublic class ScheduleService {private final Scheduler scheduler; @ Autowired public ScheduleService (Scheduler scheduler) {/ / injection scheduler this.scheduler = scheduler Try {addJobListener (); addCalendar (); scheduleJob ();} catch (SchedulerException e) {log.error (e.getMessage (), e);}} public void unscheduleJob (String jobName) throws SchedulerException {scheduler.pauseJob (JobKey.jobKey (jobName, GROUP_NAME)); scheduler.unscheduleJob (TriggerKey.triggerKey (jobName, GROUP_NAME)) Immediately trigger job * / public void triggerJob (String jobName) throws SchedulerException {scheduler.triggerJob (JobKey.jobKey (jobName, GROUP_NAME));} private void addJobListener () throws SchedulerException {UnscheduleJobListener jobListener = new UnscheduleJobListener (); GroupMatcher groupMatcher = GroupMatcher.jobGroupEquals (GROUP_NAME); this.scheduler.getListenerManager () .addJobListener (jobListener, groupMatcher) } private void addCalendar () throws SchedulerException {WeeklyCalendar calendar = new WeeklyCalendar (); calendar.setDayExcluded (1, true); / / exclude Sunday calendar.setDayExcluded (7, false); this.scheduler.addCalendar ("weekly", calendar, false, false);} private void scheduleJob () throws SchedulerException {JobDetail jobDetail = createJobDetail (); Trigger trigger = createTrigger (jobDetail); scheduler.scheduleJob (jobDetail, trigger) } private JobDetail createJobDetail () {JobDataMap jobDataMap = new JobDataMap (); / / add Job data jobDataMap.put (JOB_NAME, "getHeroes"); jobDataMap.put (JOB_REST_URI, "http://localhost:8080/api/heroes"); jobDataMap.put (JOB_REQUEST_METHOD," GET ")) Return JobBuilder.newJob (RestJob.class) .withIdentity ("getHeroes", GROUP_NAME) .usingJobData (jobDataMap). StoreDurably (). Build ();} private Trigger createTrigger (JobDetail jobDetail) {DailyTimeIntervalScheduleBuilder scheduleBuilder = DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule (). WithIntervalInMinutes (1). OnEveryDay (); return TriggerBuilder.newTrigger (). ForJob (jobDetail). WithIdentity ("getHeroes", GROUP_NAME). Withschedule (scheduleBuilder) .modifiedByCalendar ("weekly"). Build ();}}

Job definition

The following Job invokes the REST service, and adds the stop flag to the JobExecutionContext after a successful call:

Package org.itrunner.heroes.scheduling;import lombok.extern.slf4j.Slf4j;import org.quartz.JobDataMap;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpMethod;import org.springframework.http.ResponseEntity;import org.springframework.scheduling.quartz.QuartzJobBean;import java.util.List;import static org.itrunner.heroes.scheduling.Constants.JOB_REST_URI;import static org.itrunner.heroes.scheduling.Constants.JOB_STOP_FLAG Slf4jpublic class RestJob extends QuartzJobBean {@ Autowired private RestService restService; @ Override protected void executeInternal (JobExecutionContext jobExecutionContext) throws JobExecutionException {JobDataMap jobDataMap = jobExecutionContext.getMergedJobDataMap (); String restUri = jobDataMap.getString (JOB_REST_URI); ResponseEntity responseEntity = restService.requestForEntity (restUri, HttpMethod.GET, List.class); log.info (responseEntity.getBody (). ToString ()); / / set stop flag jobExecutionContext.put (JOB_STOP_FLAG, true);}}

JobListener

UnscheduleJobListener checks JobExecutionContext to see if there is a stop flag, and if so, stop Job:

Package org.itrunner.heroes.scheduling;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import org.quartz.JobListener;import org.quartz.SchedulerException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class UnscheduleJobListener implements JobListener {private static Logger log = LoggerFactory.getLogger (UnscheduleJobListener.class); @ Override public String getName () {return "HERO_UnscheduleJobListener" @ Override public void jobToBeExecuted (JobExecutionContext context) {log.info (getJobName (context) + "is about to be executed.");} @ Override public void jobExecutionVetoed (JobExecutionContext context) {log.info (getJobName (context) + "Execution was vetoed.");} @ Override public void jobWasExecuted (JobExecutionContext context, JobExecutionException jobException) {log.info (getJobName (context) + "was executed.") Boolean stop = (Boolean) context.get (Constants.JOB_STOP_FLAG); if (stop = = null | |! stop) {return;} String jobName = getJobName (context); log.info ("Unschedule" + jobName); try {context.getScheduler (). UnscheduleJob (context.getTrigger (). GetKey ()) } catch (SchedulerException e) {log.error ("Unable to unschedule" + jobName, e);}} private String getJobName (JobExecutionContext context) {return "Hero job" + context.getJobDetail (). GetKey (). GetName ();}}

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report