暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

springboot quartz定时任务调度

开发架构二三事 2019-08-28
904


几种任务调度

  • Timer,简单无门槛,一般也没人用。

  • ScheduledExecutorService主要用于一些单进程的简单的任务调度。

  • spring @Scheduled注解,一般集成于项目中,小任务很方便。

  • 开源工具 Quartz,分布式集群开源工具,以下两个分布式任务应该都是基于Quartz实现的,可以说是中小型公司必选,当然也视自身需求而定。

  • 分布式任务 XXL-JOB,是一个轻量级分布式任务调度框架,支持通过 Web 页面对任务进行 CRUD 操作,支持动态修改任务状态、暂停/恢复任务,以及终止运行中任务,支持在线配置调度任务入参和在线查看调度结果。

  • 分布式任务 Elastic-Job,是一个分布式调度解决方案,由两个相互独立的子项目 Elastic-Job-Lite 和 Elastic-Job-Cloud 组成。定位为轻量级无中心化解决方案,使用 jar 包的形式提供分布式任务的协调服务。支持分布式调度协调、弹性扩容缩容、失效转移、错过执行作业重触发、并行调度、自诊。

  • 分布式任务 Saturn,Saturn是唯品会在github开源的一款分布式任务调度产品。它是基于当当elastic-job来开发的,其上完善了一些功能和添加了一些新的feature。目前在github上开源大半年,470个star。Saturn的任务可以用多种语言开发比如python、Go、Shell、Java、Php。其在唯品会内部已经发部署350+个节点,每天任务调度4000多万次。同时,管理和统计也是它的亮点。

quartz

springboot 1.0时代

引入依赖

  1. <!--quartz相关依赖-->

  2. <dependency>

  3. <groupId>org.quartz-scheduler</groupId>

  4. <artifactId>quartz</artifactId>

  5. <version>${quartz.version}</version>

  6. </dependency>

  7. <dependency>

  8. <groupId>org.quartz-scheduler</groupId>

  9. <artifactId>quartz-jobs</artifactId>

  10. <version>${quartz.version}</version>

  11. </dependency>

配置

配置类

  1. @Configuration

  2. public class JobScheduleConfig {

  3. @Autowired

  4. private ApplicationContext applicationContext;

  5. @Bean

  6. public SchedulerFactoryBean schedulerFactoryBean() throws IOException {

  7. SchedulerFactoryBean factory = new SchedulerFactoryBean();

  8. factory.setOverwriteExistingJobs(true);

  9. factory.setAutoStartup(true);

  10. //设置线程池

  11. factory.setTaskExecutor(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2,

  12. new ThreadFactoryBuilder().setNameFormat("job-schedule-factory-thread-%d").build()));

  13. // factory.setQuartzProperties(quartzProperties());

  14. AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory();

  15. jobFactory.setApplicationContext(applicationContext);

  16. factory.setJobFactory(jobFactory);

  17. return factory;

  18. }

factory类

  1. public final class AutoWiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

  2. private transient AutowireCapableBeanFactory beanFactory;

  3. @Override

  4. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

  5. beanFactory = applicationContext.getAutowireCapableBeanFactory();

  6. }

  7. @Override

  8. protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {

  9. final Object job = super.createJobInstance(bundle);

  10. beanFactory.autowireBean(job);

  11. return job;

  12. }

  13. }

job factory

  1. @Component

  2. public class SchedulerJobFactory {

  3. public JobDetailFactoryBean job(Class<? extends QuartzJobBean> jobClass, JobDataMap jobMap, String jobName) {

  4. JobDetailFactoryBean jBean = createJobDetail(jobClass);

  5. jBean.setJobDataMap(jobMap);

  6. jBean.setBeanName(jobName);

  7. jBean.afterPropertiesSet();

  8. return jBean;

  9. }

  10. private JobDetailFactoryBean createJobDetail(Class<? extends QuartzJobBean> jobClass) {

  11. JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();

  12. factoryBean.setJobClass(jobClass);

  13. factoryBean.setDurability(true);

  14. factoryBean.setRequestsRecovery(true);

  15. factoryBean.setBeanName(jobClass.getName());

  16. return factoryBean;

  17. }

  18. }

trigger factory

  1. @Component

  2. public class SchedulerTriggerFactory {

  3. public CronTriggerFactoryBean jobTrigger(JobDetail jobDetail, String frequency, String triggerName) throws ParseException {

  4. CronTriggerFactoryBean tBean = createCronTrigger(jobDetail, frequency);

  5. tBean.setBeanName(triggerName);

  6. tBean.afterPropertiesSet();

  7. return tBean;

  8. }

  9. private CronTriggerFactoryBean createCronTrigger(JobDetail jobDetail, String cronExpression) {

  10. CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();

  11. factoryBean.setJobDetail(jobDetail);

  12. factoryBean.setCronExpression(cronExpression);

  13. factoryBean.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW);

  14. return factoryBean;

  15. }

  16. }

service:

  1. @Service

  2. public class SchedulerJobService {

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

  4. @Autowired

  5. private SchedulerFactoryBean schedulerFactoryBean;

  6. @Autowired

  7. private SchedulerJobFactory schedulerJobFactory;

  8. @Autowired

  9. private SchedulerTriggerFactory schedulerTriggerFactory;

  10. @Resource

  11. private ApplicationContext applicationContext;

  12. @PostConstruct

  13. public void setupJobs() throws ParseException, SchedulerException {

  14. Map<String, AStandardBaseJob> beanMap = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext,

  15. AStandardBaseJob.class);

  16. LOGGER.info("【task扫描注册已启动】-共找到task数为[{}]", beanMap != null ? beanMap.size() : 0);

  17. beanMap.keySet().forEach(key -> {

  18. AStandardBaseJob aStandardBaseJob = beanMap.get(key);

  19. String className = aStandardBaseJob.getClass().getName();

  20. LOGGER.info("[------------扫描到的任务的名称为:" + className + "----------------------]");

  21. });

  22. if (beanMap != null && beanMap.size() > 0) {

  23. beanMap.forEach((key, value) -> {

  24. if (!this.baseCheck(value)) {

  25. return;

  26. }

  27. try {

  28. scheduleJob(value.getClass(), null, value.initCronValue(), StringBuilderHolder.getGlobal().

  29. append(value.initAppId()).append("-").append(value.initCronKey()).toString(),

  30. value.initCronKey());

  31. } catch (ParseException e) {

  32. e.printStackTrace();

  33. } catch (SchedulerException e) {

  34. e.printStackTrace();

  35. }

  36. });

  37. }

  38. // scheduleJob(ContentStatisticsJob.class, null, "1/1 * * * * ?",

  39. // "exampleJob", "trigger1");

  40. }

  41. public Date scheduleJob(Class<? extends QuartzJobBean> object, JobDataMap jMap, String frequency, String jobName,

  42. String triggerName) throws ParseException, SchedulerException {

  43. JobDetailFactoryBean jobDetailFactoryBean = schedulerJobFactory.job(object, jMap, jobName);

  44. CronTriggerFactoryBean cronTriggerFactoryBean = schedulerTriggerFactory

  45. .jobTrigger(jobDetailFactoryBean.getObject(), frequency, triggerName);

  46. return schedulerFactoryBean.getScheduler().scheduleJob(jobDetailFactoryBean.getObject(),

  47. cronTriggerFactoryBean.getObject());

  48. }

  49. /**

  50. * 基本校验

  51. *

  52. * @Description

  53. * @param aTaskStandardJob

  54. * @return

  55. */

  56. public boolean baseCheck(AStandardBaseJob aTaskStandardJob) {

  57. if (StringUtils.isBlank(aTaskStandardJob.initAppId())) {

  58. LOGGER.error("【task扫描注册出现异常】-类[{}]-[appId]-不能为空", aTaskStandardJob.getClass());

  59. return false;

  60. }

  61. if (StringUtils.isBlank(aTaskStandardJob.initCronKey())) {

  62. LOGGER.error("【task扫描注册出现异常】-类[{}]-[CronKey]-不能为空", aTaskStandardJob.getClass());

  63. return false;

  64. }

  65. if (StringUtils.isBlank(aTaskStandardJob.initCronValue())) {

  66. LOGGER.error("【task扫描注册出现异常】-类[{}]-[CronValue]-不能为空", aTaskStandardJob.getClass());

  67. return false;

  68. }

  69. if (aTaskStandardJob.initValidSign() == BaseGlobalConstants.VALID_SIGN_N) {

  70. LOGGER.info("【task扫描注册】-类[{}]-[valid_sign]-为无效", aTaskStandardJob.getClass());

  71. return false;

  72. }

  73. return true;

  74. }

  75. }

通用job:

  1. public abstract class AStandardBaseJob extends QuartzJobBean{

  2. /**

  3. * 初始化appid

  4. *

  5. * @Description

  6. * @return appId

  7. */

  8. public abstract String initAppId();

  9. /**

  10. * 初始化Cron表达式key

  11. *

  12. * @Description

  13. * @return cronKey

  14. */

  15. public abstract String initCronKey();

  16. /**

  17. * 初始化Cron表达式值

  18. *

  19. * @Description

  20. * @return 表达式值

  21. */

  22. public abstract String initCronValue();

  23. /**

  24. * 初始化有效标志

  25. *

  26. * @Description

  27. * @return 表达式值

  28. */

  29. public abstract int initValidSign();

  30. }

springboot 2.0时代

引入依赖

  1. <!--quartz依赖-->

  2. <dependency>

  3. <groupId>org.springframework.boot</groupId>

  4. <artifactId>spring-boot-starter-quartz</artifactId>

  5. </dependency>

在我们添加spring-boot-starter-quartz依赖后就不需要主动声明工厂类,因为spring-boot-starter-quartz已经为我们自动化配置好了。展开spring-boot-autoconfigure-2.0.0.RELEASE.jar,找到org.springframework.boot.autoconfigure.quartz,该目录就是SpringBoot为我们提供的Quartz自动化配置源码实现,在该目录下有如下所示几个类:

  • AutowireCapableBeanJobFactory 该类替代了我们之前在QuartzConfiguration配置类的AutowiringSpringBeanJobFactory内部类实现,主要作用是我们自定义的QuartzJobBean子类被Spring IOC进行托管,可以在定时任务类内使用注入任意被Spring IOC托管的类。

  • JobStoreType 该类是一个枚举类型,定义了对应application.yml、application.properties文件内spring.quartz.job-store-type配置,其目的是配置quartz任务的数据存储方式,分别为:MEMORY(内存方式:默认)、JDBC(数据库方式)。

  • QuartzAutoConfiguration 该类是自动配置的主类,内部配置了SchedulerFactoryBean以及JdbcStoreTypeConfiguration,使用QuartzProperties作为属性自动化配置条件。

  • QuartzDataSourceInitializer 该类主要用于数据源初始化后的一些操作,根据不同平台类型的数据库进行选择不同的数据库脚本。

  • QuartzProperties 该类对应了spring.quartz在application.yml、application.properties文件内开头的相关配置。

  • SchedulerFactoryBeanCustomizer 这是一个接口,我们实现该接口后并且将实现类使用Spring IOC托管,可以完成SchedulerFactoryBean的个性化设置,这里的设置完全可以对SchedulerFactoryBean做出全部的设置变更。

  • spring.quartz.properties 该配置其实代替了之前的quartz.properties,我们把之前quartz.properties配置文件内的所有配置转换成YAML风格,对应的添加在该配置下即可,在QuartzAutoConfiguration类内,会自动调用SchedulerFactoryBean的setQuartzProperties方法,把spring.quartz.properties内的所有配置进行设置。

实战

表说明

  1. DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;

  2. DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;

  3. DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;

  4. DROP TABLE IF EXISTS QRTZ_LOCKS;

  5. DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;

  6. DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;

  7. DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;

  8. DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;

  9. DROP TABLE IF EXISTS QRTZ_TRIGGERS;

  10. DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;

  11. DROP TABLE IF EXISTS QRTZ_CALENDARS;

  12. CREATE TABLE QRTZ_JOB_DETAILS(

  13. SCHED_NAME VARCHAR(120) NOT NULL,

  14. JOB_NAME VARCHAR(200) NOT NULL,

  15. JOB_GROUP VARCHAR(200) NOT NULL,

  16. DESCRIPTION VARCHAR(250) NULL,

  17. JOB_CLASS_NAME VARCHAR(250) NOT NULL,

  18. IS_DURABLE VARCHAR(1) NOT NULL,

  19. IS_NONCONCURRENT VARCHAR(1) NOT NULL,

  20. IS_UPDATE_DATA VARCHAR(1) NOT NULL,

  21. REQUESTS_RECOVERY VARCHAR(1) NOT NULL,

  22. JOB_DATA BLOB NULL,

  23. PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))

  24. ENGINE=InnoDB;

  25. CREATE TABLE QRTZ_TRIGGERS (

  26. SCHED_NAME VARCHAR(120) NOT NULL,

  27. TRIGGER_NAME VARCHAR(200) NOT NULL,

  28. TRIGGER_GROUP VARCHAR(200) NOT NULL,

  29. JOB_NAME VARCHAR(200) NOT NULL,

  30. JOB_GROUP VARCHAR(200) NOT NULL,

  31. DESCRIPTION VARCHAR(250) NULL,

  32. NEXT_FIRE_TIME BIGINT(13) NULL,

  33. PREV_FIRE_TIME BIGINT(13) NULL,

  34. PRIORITY INTEGER NULL,

  35. TRIGGER_STATE VARCHAR(16) NOT NULL,

  36. TRIGGER_TYPE VARCHAR(8) NOT NULL,

  37. START_TIME BIGINT(13) NOT NULL,

  38. END_TIME BIGINT(13) NULL,

  39. CALENDAR_NAME VARCHAR(200) NULL,

  40. MISFIRE_INSTR SMALLINT(2) NULL,

  41. JOB_DATA BLOB NULL,

  42. PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),

  43. FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)

  44. REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))

  45. ENGINE=InnoDB;

  46. CREATE TABLE QRTZ_SIMPLE_TRIGGERS (

  47. SCHED_NAME VARCHAR(120) NOT NULL,

  48. TRIGGER_NAME VARCHAR(200) NOT NULL,

  49. TRIGGER_GROUP VARCHAR(200) NOT NULL,

  50. REPEAT_COUNT BIGINT(7) NOT NULL,

  51. REPEAT_INTERVAL BIGINT(12) NOT NULL,

  52. TIMES_TRIGGERED BIGINT(10) NOT NULL,

  53. PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),

  54. FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)

  55. REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))

  56. ENGINE=InnoDB;

  57. CREATE TABLE QRTZ_CRON_TRIGGERS (

  58. SCHED_NAME VARCHAR(120) NOT NULL,

  59. TRIGGER_NAME VARCHAR(200) NOT NULL,

  60. TRIGGER_GROUP VARCHAR(200) NOT NULL,

  61. CRON_EXPRESSION VARCHAR(120) NOT NULL,

  62. TIME_ZONE_ID VARCHAR(80),

  63. PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),

  64. FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)

  65. REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))

  66. ENGINE=InnoDB;

  67. CREATE TABLE QRTZ_SIMPROP_TRIGGERS

  68. (

  69. SCHED_NAME VARCHAR(120) NOT NULL,

  70. TRIGGER_NAME VARCHAR(200) NOT NULL,

  71. TRIGGER_GROUP VARCHAR(200) NOT NULL,

  72. STR_PROP_1 VARCHAR(512) NULL,

  73. STR_PROP_2 VARCHAR(512) NULL,

  74. STR_PROP_3 VARCHAR(512) NULL,

  75. INT_PROP_1 INT NULL,

  76. INT_PROP_2 INT NULL,

  77. LONG_PROP_1 BIGINT NULL,

  78. LONG_PROP_2 BIGINT NULL,

  79. DEC_PROP_1 NUMERIC(13,4) NULL,

  80. DEC_PROP_2 NUMERIC(13,4) NULL,

  81. BOOL_PROP_1 VARCHAR(1) NULL,

  82. BOOL_PROP_2 VARCHAR(1) NULL,

  83. PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),

  84. FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)

  85. REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))

  86. ENGINE=InnoDB;

  87. CREATE TABLE QRTZ_BLOB_TRIGGERS (

  88. SCHED_NAME VARCHAR(120) NOT NULL,

  89. TRIGGER_NAME VARCHAR(200) NOT NULL,

  90. TRIGGER_GROUP VARCHAR(200) NOT NULL,

  91. BLOB_DATA BLOB NULL,

  92. PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),

  93. INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),

  94. FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)

  95. REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))

  96. ENGINE=InnoDB;

  97. CREATE TABLE QRTZ_CALENDARS (

  98. SCHED_NAME VARCHAR(120) NOT NULL,

  99. CALENDAR_NAME VARCHAR(200) NOT NULL,

  100. CALENDAR BLOB NOT NULL,

  101. PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))

  102. ENGINE=InnoDB;

  103. CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (

  104. SCHED_NAME VARCHAR(120) NOT NULL,

  105. TRIGGER_GROUP VARCHAR(200) NOT NULL,

  106. PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))

  107. ENGINE=InnoDB;

  108. CREATE TABLE QRTZ_FIRED_TRIGGERS (

  109. SCHED_NAME VARCHAR(120) NOT NULL,

  110. ENTRY_ID VARCHAR(95) NOT NULL,

  111. TRIGGER_NAME VARCHAR(200) NOT NULL,

  112. TRIGGER_GROUP VARCHAR(200) NOT NULL,

  113. INSTANCE_NAME VARCHAR(200) NOT NULL,

  114. FIRED_TIME BIGINT(13) NOT NULL,

  115. SCHED_TIME BIGINT(13) NOT NULL,

  116. PRIORITY INTEGER NOT NULL,

  117. STATE VARCHAR(16) NOT NULL,

  118. JOB_NAME VARCHAR(200) NULL,

  119. JOB_GROUP VARCHAR(200) NULL,

  120. IS_NONCONCURRENT VARCHAR(1) NULL,

  121. REQUESTS_RECOVERY VARCHAR(1) NULL,

  122. PRIMARY KEY (SCHED_NAME,ENTRY_ID))

  123. ENGINE=InnoDB;

  124. CREATE TABLE QRTZ_SCHEDULER_STATE (

  125. SCHED_NAME VARCHAR(120) NOT NULL,

  126. INSTANCE_NAME VARCHAR(200) NOT NULL,

  127. LAST_CHECKIN_TIME BIGINT(13) NOT NULL,

  128. CHECKIN_INTERVAL BIGINT(13) NOT NULL,

  129. PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))

  130. ENGINE=InnoDB;

  131. CREATE TABLE QRTZ_LOCKS (

  132. SCHED_NAME VARCHAR(120) NOT NULL,

  133. LOCK_NAME VARCHAR(40) NOT NULL,

  134. PRIMARY KEY (SCHED_NAME,LOCK_NAME))

  135. ENGINE=InnoDB;

  136. CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);

  137. CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);

  138. CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);

  139. CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);

  140. CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);

  141. CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);

  142. CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);

  143. CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);

  144. CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);

  145. CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);

  146. CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);

  147. CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);

  148. CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);

  149. CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);

  150. CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);

  151. CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);

  152. CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);

  153. CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);

  154. CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);

  155. CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);

  156. commit;

说明:

  • QRTZ_CALENDARS 以 Blob 类型存储 Quartz 的 Calendar 信息

  • QRTZCRONTRIGGERS 存储 Cron Trigger,包括 Cron表达式和时区信息

  • QRTZFIREDTRIGGERS 存储与已触发的 Trigger 相关的状态信息,以及相联 Job的执行信息 QRTZPAUSEDTRIGGER_GRPS 存储已暂停的 Trigger 组的信息

  • QRTZSCHEDULERSTATE 存储少量的有关 Scheduler 的状态信息,和别的 Scheduler实例(假如是用于一个集群中)

  • QRTZ_LOCKS 存储程序的悲观锁的信息(假如使用了悲观锁)

  • QRTZJOBDETAILS 存储每一个已配置的 Job 的详细信息

  • QRTZJOBLISTENERS 存储有关已配置的 JobListener 的信息

  • QRTZSIMPLETRIGGERS 存储简单的Trigger,包括重复次数,间隔,以及已触的次数

  • QRTZBLOGTRIGGERS Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候)

  • QRTZTRIGGERLISTENERS 存储已配置的 TriggerListener 的信息

  • QRTZ_TRIGGERS 存储已配置的 Trigger 的信息

表字段说明:

  1. qrtz_job_details: 保存job详细信息,该表需要用户根据实际情况初始化

  2. job_name:集群中job的名字,该名字用户自己可以随意定制,无强行要求

  3. job_group:集群中job的所属组的名字,该名字用户自己随意定制,无强行要求

  4. job_class_name:集群中个note job实现类的完全包名,quartz就是根据这个路径到classpath找到该job

  5. is_durable:是否持久化,把该属性设置为1quartz会把job持久化到数据库中

  6. job_data:一个blob字段,存放持久化job对象

  7. qrtz_triggers: 保存trigger信息

  8. trigger_name: trigger的名字,该名字用户自己可以随意定制,无强行要求

  9. trigger_group:trigger所属组的名字,该名字用户自己随意定制,无强行要求

  10. job_name: qrtz_job_detailsjob_name的外键

  11. job_group: qrtz_job_detailsjob_group的外键

  12. trigger_state:当前trigger状态,设置为ACQUIRED,如果设置为WAITING,则job不会触发;暂停任务时状态为PAUSED

  13. trigger_cron:触发器类型,使用cron表达式

  14. qrtz_cron_triggers:存储cron表达式表

  15. trigger_name: qrtz_triggerstrigger_name的外键

  16. trigger_group: qrtz_triggerstrigger_group的外键

  17. cron_expression:cron表达式

  18. qrtz_scheduler_state:存储集群中note实例信息,quartz会定时读取该表的信息判断集群中每个实例的当前状态

  19. instance_name:之前配置文件中org.quartz.scheduler.instanceId配置的名字,就会写入该字段,如果设置为AUTO,quartz会根据物理机名和当前时间产生一个名字

  20. last_checkin_time:上次检查时间

  21. checkin_interval:检查间隔时间

springboot 配置说明

  1. spring.quartz.properties.org.quartz.scheduler.instanceName = clusteredScheduler

  2. spring.quartz.properties.org.quartz.scheduler.instanceId = AUTO

  3. spring.quartz.properties.org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX

  4. spring.quartz.properties.org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate

  5. spring.quartz.properties.org.quartz.jobStore.tablePrefix = qrtz_

  6. spring.quartz.properties.org.quartz.jobStore.isClustered = true

  7. spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval = 10000

  8. spring.quartz.properties.org.quartz.jobStore.useProperties = false

  9. spring.quartz.properties.org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool

  10. spring.quartz.properties.org.quartz.threadPool.threadCount = 2

  11. spring.quartz.properties.org.quartz.threadPool.threadPriority = 2

  12. spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

  13. spring.quartz.job-store-type = jdbc

  14. spring.quartz.startup-delay=5s

  15. spring.quartz.jdbc.initialize-schema=never

  16. spring.quartz.overwrite-existing-jobs=false

执行定时任务

  1. @Component

  2. public class TaskRunner implements ApplicationRunner {

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

  4. @Autowired

  5. private IQrtzJobDetailsService jobService;

  6. @Autowired

  7. private Scheduler scheduler;

  8. @SuppressWarnings({ "rawtypes", "unchecked" })

  9. @Override

  10. public void run(ApplicationArguments var) throws Exception{

  11. Long count = jobService.countQuartzEntity();

  12. if(count==0){

  13. LOGGER.info("初始化测试任务");

  14. QuartzEntity quartz = new QuartzEntity();

  15. quartz.setJobName("test01");

  16. quartz.setJobGroup("test");

  17. quartz.setDescription("测试任务");

  18. quartz.setJobClassName("com.ambition.common.quartz.job.TestJob");

  19. quartz.setCronExpression("0/20 * * * * ?");

  20. Class cls = Class.forName(quartz.getJobClassName()) ;

  21. cls.newInstance();

  22. //构建job信息

  23. JobDetail job = JobBuilder.newJob(cls).withIdentity(quartz.getJobName(),

  24. quartz.getJobGroup())

  25. .withDescription(quartz.getDescription()).build();

  26. // 触发时间点

  27. CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartz.getCronExpression());

  28. Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger"+quartz.getJobName(), quartz.getJobGroup())

  29. .startNow().withSchedule(cronScheduleBuilder).build();

  30. //交由Scheduler安排触发

  31. scheduler.scheduleJob(job, trigger);

  32. }

  33. }

  34. }

任务类:

  1. /**

  2. * 实现序列化接口、防止重启应用出现quartz Couldn't retrieve job because a required class was not found 的问题

  3. *

  4. * Job 的实例要到该执行它们的时候才会实例化出来。每次 Job 被执行,一个新的 Job 实例会被创建。

  5. * 其中暗含的意思就是你的 Job 不必担心线程安全性,因为同一时刻仅有一个线程去执行给定 Job 类的实例,甚至是并发执行同一 Job 也是如此。

  6. * @DisallowConcurrentExecution 保证上一个任务执行完后,再去执行下一个任务,这里的任务是同一个任务

  7. */

  8. @DisallowConcurrentExecution

  9. public class TestJob implements Job,Serializable {

  10. private static final long serialVersionUID = 1L;

  11. @Override

  12. public void execute(JobExecutionContext context) throws JobExecutionException {

  13. System.out.println("任务执行成功");

  14. }

  15. }

controller类:

  1. @Api(tags ="Quartz任务")

  2. @RestController

  3. @RequestMapping("/job")

  4. public class JobController {

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

  6. @Autowired

  7. private Scheduler scheduler;

  8. @Autowired

  9. private IQrtzJobDetailsService jobService;

  10. @SuppressWarnings({ "unchecked", "rawtypes" })

  11. @ApiOperation(value="新建任务")

  12. @PostMapping("/add")

  13. public R save(QuartzEntity quartz){

  14. LOGGER.info("新增任务");

  15. try {

  16. //获取Scheduler实例、废弃、使用自动注入的scheduler、否则spring的service将无法注入

  17. //Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

  18. //如果是修改 展示旧的 任务

  19. if(quartz.getOldJobGroup()!=null){

  20. JobKey key = new JobKey(quartz.getOldJobName(),quartz.getOldJobGroup());

  21. scheduler.deleteJob(key);

  22. }

  23. Class cls = Class.forName(quartz.getJobClassName()) ;

  24. cls.newInstance();

  25. //构建job信息

  26. JobDetail job = JobBuilder.newJob(cls).withIdentity(quartz.getJobName(),

  27. quartz.getJobGroup())

  28. .withDescription(quartz.getDescription()).build();

  29. // 触发时间点

  30. CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartz.getCronExpression());

  31. Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger"+quartz.getJobName(), quartz.getJobGroup())

  32. .startNow().withSchedule(cronScheduleBuilder).build();

  33. //交由Scheduler安排触发

  34. scheduler.scheduleJob(job, trigger);

  35. } catch (Exception e) {

  36. LOGGER.error("",e);

  37. return R.error();

  38. }

  39. return R.ok();

  40. }

  41. @ApiOperation(value="任务列表")

  42. @PostMapping("/list")

  43. public R list(QuartzEntity quartz,Integer pageNo,Integer pageSize){

  44. LOGGER.info("任务列表");

  45. List<QuartzEntity> list = jobService.listQuartzEntity();

  46. return R.ok(list);

  47. }

  48. @ApiOperation(value="触发任务")

  49. @PostMapping("/trigger")

  50. public R trigger(QuartzEntity quartz, HttpServletResponse response) {

  51. try {

  52. JobKey key = new JobKey(quartz.getJobName(),quartz.getJobGroup());

  53. scheduler.triggerJob(key);

  54. } catch (SchedulerException e) {

  55. e.printStackTrace();

  56. return R.error();

  57. }

  58. return R.ok();

  59. }

  60. @PostMapping("/pause")

  61. public R pause(QuartzEntity quartz, HttpServletResponse response) {

  62. LOGGER.info("停止任务");

  63. try {

  64. JobKey key = new JobKey(quartz.getJobName(),quartz.getJobGroup());

  65. scheduler.pauseJob(key);

  66. } catch (SchedulerException e) {

  67. e.printStackTrace();

  68. return R.error();

  69. }

  70. return R.ok();

  71. }

  72. @PostMapping("/resume")

  73. public R resume(QuartzEntity quartz, HttpServletResponse response) {

  74. LOGGER.info("恢复任务");

  75. try {

  76. JobKey key = new JobKey(quartz.getJobName(),quartz.getJobGroup());

  77. scheduler.resumeJob(key);

  78. } catch (SchedulerException e) {

  79. e.printStackTrace();

  80. return R.error();

  81. }

  82. return R.ok();

  83. }

  84. @ApiOperation(value="移除任务")

  85. @PostMapping("/remove")

  86. public R remove(QuartzEntity quartz, HttpServletResponse response) {

  87. try {

  88. TriggerKey triggerKey = TriggerKey.triggerKey(quartz.getJobName(), quartz.getJobGroup());

  89. // 停止触发器

  90. scheduler.pauseTrigger(triggerKey);

  91. // 移除触发器

  92. scheduler.unscheduleJob(triggerKey);

  93. // 删除任务

  94. scheduler.deleteJob(JobKey.jobKey(quartz.getJobName(), quartz.getJobGroup()));

  95. System.out.println("removeJob:"+ JobKey.jobKey(quartz.getJobName()));

  96. } catch (Exception e) {

  97. e.printStackTrace();

  98. return R.error();

  99. }

  100. return R.ok();

  101. }

  102. }

可以通过controller提供的接口进行任务的动态添加和删除,也可以和TaskRunner那样硬编码加载任务。

文章转载自开发架构二三事,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论