Quartz的持久化存储
撰写背景
工作中遇到的需求,这里展示了两种方法,区别只在于配置文件的位置,其他步骤一致
建表
官方提供内置表:https://www.quartz-scheduler.org/downloads/
这里我选择的是2.3.0版,建表sql在
quartz-2.3.0-SNAPSHOT\src\org\quartz\impl\jdbcjobstore\tables_mysql.sql这个目录下
- qrtz_blob_triggers : 以Blob 类型存储的触发器。
- qrtz_calendars:存放日历信息, quartz可配置一个日历来指定一个时间范围。
- qrtz_cron_triggers:存放cron类型的触发器。
- qrtz_fired_triggers:存放已触发的触发器。
- qrtz_job_details:存放一个jobDetail信息。
- qrtz_locks: 存储程序的悲观锁的信息(假如使用了悲观锁)。
- qrtz_paused_trigger_grps:存放暂停掉的触发器。
- qrtz_scheduler_state:调度器状态。
- qrtz_simple_triggers:简单触发器的信息。
- qrtz_simprop_triggers:存储CalendarIntervalTrigger和DailyTimeIntervalTrigger两种类型的触发器。
- qrtz_triggers:触发器的基本信息。
引入依赖
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
|
方法一
加入properties配置文件
quartz.properties:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.instanceName=project1QuartzScheduler org.quartz.scheduler.rmi.export=false org.quartz.scheduler.rmi.proxy=false
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=5
org.quartz.threadPool.threadPriority=5 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
org.quartz.jobStore.misfireThreshold=60000
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.isClustered=false
org.quartz.jobStore.tablePrefix=qrtz_
org.quartz.jobStore.dataSource=myDS
org.quartz.dataSource.myDS.driver= com.mysql.cj.jdbc.Driver
org.quartz.dataSource.myDS.URL=
org.quartz.dataSource.myDS.user=
org.quartz.dataSource.myDS.password=
org.quartz.dataSource.myDS.maxConnections= 5
org.quartz.dataSource.myDS.validateOnCheckout=true org.quartz.dataSource.myDS.validationQuery=SELECT 'x'
|
增加配置类
为了扫描到Quartz的配置文件并将Quartz注入到SpringBoot中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| @Configuration @Slf4j public class QuartzConfig { @Autowired private JobFactory jobFactory;
@Autowired private AutowireCapableBeanFactory capableBeanFactory;
@Bean public JobFactory jobFactory() { return new AdaptableJobFactory() { @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { Object jobInstance = super.createJobInstance(bundle); capableBeanFactory.autowireBean(jobInstance); return jobInstance; } }; }
@Bean public SchedulerFactoryBean schedulerFactoryBean() { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setJobFactory(jobFactory); schedulerFactoryBean.setStartupDelay(1); Properties properties = getProperties("quartz.properties"); schedulerFactoryBean.setQuartzProperties(properties); return schedulerFactoryBean; }
public static Properties getProperties(String fileName) { Properties properties = new Properties(); try { String outpath = System.getProperty("user.dir") + File.separator + "config" + File.separator; System.out.println(outpath); InputStream in = Files.newInputStream(new File(outpath + fileName).toPath()); properties.load(in); } catch (IOException e) { log.info("获取quartz配置异常:{}",e.getMessage(),e); } return properties; }
@Bean public Scheduler scheduler() { return schedulerFactoryBean().getScheduler(); } }
|
方法二(要求SpringBoot2.0版本及以后)
SpringBoot2.0版本及以后的版本集成了Quartz,无需再手动编写properties文件和配置类了,与方法一的区别仅仅只有这个。
yml里集成Quartz配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| spring: quartz: job-store-type: jdbc jdbc: initialize-schema: always properties: org.quartz.scheduler.instanceId: AUTO org.quartz.scheduler.instanceName: projectQuartzScheduler1 org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount: 10 org.quartz.threadPool.threadPriority: 5 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.tablePrefix: qrtz_ org.quartz.jobStore.isClustered: true org.quartz.jobStore.dataSource: myDS org.quartz.jobStore.misfireThreshold: 60000 org.quartz.dataSource.myDS.driver: com.mysql.cj.jdbc.Driver org.quartz.dataSource.myDS.URL: org.quartz.dataSource.myDS.user: org.quartz.dataSource.myDS.password: org.quartz.scheduler.rmi.export: false org.quartz.scheduler.rmi.proxy: false
|
编写调用类
需求业务编写的地方
1 2 3 4 5 6
| @Slf4j public class SendOrder extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("abc"); }
|
新增和修改Job
注:PageData类似Map<String,Object>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| @Slf4j @Component public class QuartzJob {
@Autowired private Scheduler scheduler;
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
public void start() throws Exception { scheduler.start(); }
public void createJob(PageData pd) throws Exception { Class<org.quartz.Job> clazz; try { clazz = (Class<org.quartz.Job>) Class.forName("你需要执行类的类路径"); } catch (ClassNotFoundException e1) { throw new RuntimeException(e1); } JobDetail jobDetail = JobBuilder.newJob(clazz) .usingJobData("planId", String.valueOf(pd.get("planId"))) .withIdentity(String.valueOf(pd.get("planId"))) .build(); String cron = String.valueOf(pd.get("cronName")); CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron).withMisfireHandlingInstructionDoNothing(); CronTrigger cronTrigger = TriggerBuilder.newTrigger() .forJob(jobDetail) .withSchedule(cronScheduleBuilder) .withIdentity(String.valueOf(pd.get("planId"))) .startAt(dateFormat.parse(String.valueOf(pd.get("planStartDate")))) .endAt(dateFormat.parse(String.valueOf(pd.get("planEndDate")))) .build(); scheduler.scheduleJob(jobDetail, cronTrigger); log.info("当前job创建成功:{}", pd.get("planId")); }
public void updateJob(PageData pd) throws Exception {
TriggerKey triggerKey = new TriggerKey(String.valueOf(pd.get("planId")));
CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if(cronTrigger==null){ createJob(pd); }else{ String oldTime = cronTrigger.getCronExpression(); if (!oldTime.equals(String.valueOf(pd.get("cronName")))) { CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(String.valueOf(pd.get("cronName"))).withMisfireHandlingInstructionDoNothing(); CronTrigger cronTrigger1 = TriggerBuilder.newTrigger() .withIdentity(String.valueOf(pd.get("planId"))) .withSchedule(cronScheduleBuilder) .startAt(dateFormat.parse(String.valueOf(pd.get("planStartDate")))) .endAt(dateFormat.parse(String.valueOf(pd.get("planEndDate")))) .build(); scheduler.rescheduleJob(triggerKey, cronTrigger1); log.info("监听到修改,任务“{}”发生修改,修改前cron表达式为:{} ,修改后cron表达式为: {}", pd.get("planId"), oldTime, pd.get("cronName")); } } } }
|
调度器的初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Slf4j @Component @Order(5) public class QuartzStart implements CommandLineRunner {
@Autowired QuartzJob quartzJob;
@Override public void run(String... args) throws Exception { try { quartzJob.start(); } catch (Exception e) { throw new RuntimeException(e); } System.out.println("==============调度任务已经启动=========="); } }
|
扩展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| @Slf4j @Component public class JobControl { @Autowired Scheduler scheduler;
public void addJob(Class <? extends Job> jobClass,String jName, String jGroup, String tName, String tGroup, String cron) { try { JobDetail jobDetail = JobBuilder.newJob(jobClass) .withIdentity(jName, jGroup) .build(); CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(tName, tGroup) .startNow() .withSchedule(CronScheduleBuilder.cronSchedule(cron)) .build(); scheduler.start(); scheduler.scheduleJob(jobDetail, trigger); } catch (Exception e) { e.printStackTrace(); }
}
public void pauseJob(String jName, String jGroup) { try { scheduler.pauseJob(JobKey.jobKey(jName, jGroup)); } catch (Exception e) { e.printStackTrace(); } }
public void resumeJob(String jName, String jGroup) { try { scheduler.resumeJob(JobKey.jobKey(jName, jGroup)); } catch (SchedulerException e) { e.printStackTrace(); } }
public void deleteJob(String jName, String jGroup) { try { scheduler.deleteJob(JobKey.jobKey(jName, jGroup)); } catch (SchedulerException e) { e.printStackTrace(); } } }
|