SpringBoot - 集成Quartz框架之具体步骤(三)_quartz集成-程序员宅基地

技术标签: spring boot  quartz  SpringBoot  

写在前面

本文讲述在基于SpringBoot框架的项目中,如何一步一步的集成Quartz框架,项目使用的是PostgreSQL数据库。

具体步骤

1. 添加依赖
<!-- quartz -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
2. 编写配置

在resource目录下创建servicex-quartz.properties文件:

#============================================================================
# 1. 基本配置
#============================================================================

# 调度标识名, 集群中每一个实例都必须使用相同的名称
org.quartz.scheduler.instanceName = SERVICEX-SCHEDULER-INSTANCE-NAME
# ID设置为自动获取, 每一个实例不能相同
org.quartz.scheduler.instanceId = AUTO

#============================================================================
# 2. 调度器线程池配置
#============================================================================

# 线程池的实现类, 一般使用SimpleThreadPool即可满足需求
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# 指定线程数无默认值, 至少为1
org.quartz.threadPool.threadCount = 10
# 设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
org.quartz.threadPool.threadPriority = 5


#============================================================================
# 3. 作业存储配置
#============================================================================

# 数据保存方式为数据库持久化
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
# 数据库驱动
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
# 是否加入集群
org.quartz.jobStore.isClustered = true
# 检查集群节点状态的频率, 默认值是 15000(15)
org.quartz.jobStore.clusterCheckinInterval = 15000
org.quartz.jobStore.maxMisfiresToHandleAtATime = 1
org.quartz.jobStore.txIsolationLevelSerializable = true
# 设置调度引擎对触发器超时的忍耐时间 (单位毫秒)
org.quartz.jobStore.misfireThreshold = 12000
# 表的前缀,默认QRTZ_
org.quartz.jobStore.tablePrefix = QRTZ_
3. 建库建表

在官网中找到对于的SQL脚本:

-- Thanks to Patrick Lightbody for submitting this...
--
-- In your Quartz properties file, you'll need to set
-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;

CREATE TABLE QRTZ_JOB_DETAILS
(
  SCHED_NAME        VARCHAR(120) NOT NULL,
  JOB_NAME          VARCHAR(200) NOT NULL,
  JOB_GROUP         VARCHAR(200) NOT NULL,
  DESCRIPTION       VARCHAR(250) NULL,
  JOB_CLASS_NAME    VARCHAR(250) NOT NULL,
  IS_DURABLE        BOOL         NOT NULL,
  IS_NONCONCURRENT  BOOL         NOT NULL,
  IS_UPDATE_DATA    BOOL         NOT NULL,
  REQUESTS_RECOVERY BOOL         NOT NULL,
  JOB_DATA          BYTEA        NULL,
  PRIMARY KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
);

CREATE TABLE QRTZ_TRIGGERS
(
  SCHED_NAME     VARCHAR(120) NOT NULL,
  TRIGGER_NAME   VARCHAR(200) NOT NULL,
  TRIGGER_GROUP  VARCHAR(200) NOT NULL,
  JOB_NAME       VARCHAR(200) NOT NULL,
  JOB_GROUP      VARCHAR(200) NOT NULL,
  DESCRIPTION    VARCHAR(250) NULL,
  NEXT_FIRE_TIME BIGINT       NULL,
  PREV_FIRE_TIME BIGINT       NULL,
  PRIORITY       INTEGER      NULL,
  TRIGGER_STATE  VARCHAR(16)  NOT NULL,
  TRIGGER_TYPE   VARCHAR(8)   NOT NULL,
  START_TIME     BIGINT       NOT NULL,
  END_TIME       BIGINT       NULL,
  CALENDAR_NAME  VARCHAR(200) NULL,
  MISFIRE_INSTR  SMALLINT     NULL,
  JOB_DATA       BYTEA        NULL,
  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
  REFERENCES QRTZ_JOB_DETAILS (SCHED_NAME, JOB_NAME, JOB_GROUP)
);

CREATE TABLE QRTZ_SIMPLE_TRIGGERS
(
  SCHED_NAME      VARCHAR(120) NOT NULL,
  TRIGGER_NAME    VARCHAR(200) NOT NULL,
  TRIGGER_GROUP   VARCHAR(200) NOT NULL,
  REPEAT_COUNT    BIGINT       NOT NULL,
  REPEAT_INTERVAL BIGINT       NOT NULL,
  TIMES_TRIGGERED BIGINT       NOT NULL,
  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CRON_TRIGGERS
(
  SCHED_NAME      VARCHAR(120) NOT NULL,
  TRIGGER_NAME    VARCHAR(200) NOT NULL,
  TRIGGER_GROUP   VARCHAR(200) NOT NULL,
  CRON_EXPRESSION VARCHAR(120) NOT NULL,
  TIME_ZONE_ID    VARCHAR(80),
  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
);

CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
  SCHED_NAME    VARCHAR(120)   NOT NULL,
  TRIGGER_NAME  VARCHAR(200)   NOT NULL,
  TRIGGER_GROUP VARCHAR(200)   NOT NULL,
  STR_PROP_1    VARCHAR(512)   NULL,
  STR_PROP_2    VARCHAR(512)   NULL,
  STR_PROP_3    VARCHAR(512)   NULL,
  INT_PROP_1    INT            NULL,
  INT_PROP_2    INT            NULL,
  LONG_PROP_1   BIGINT         NULL,
  LONG_PROP_2   BIGINT         NULL,
  DEC_PROP_1    NUMERIC(13, 4) NULL,
  DEC_PROP_2    NUMERIC(13, 4) NULL,
  BOOL_PROP_1   BOOL           NULL,
  BOOL_PROP_2   BOOL           NULL,
  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
);

CREATE TABLE QRTZ_BLOB_TRIGGERS
(
  SCHED_NAME    VARCHAR(120) NOT NULL,
  TRIGGER_NAME  VARCHAR(200) NOT NULL,
  TRIGGER_GROUP VARCHAR(200) NOT NULL,
  BLOB_DATA     BYTEA        NULL,
  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CALENDARS
(
  SCHED_NAME    VARCHAR(120) NOT NULL,
  CALENDAR_NAME VARCHAR(200) NOT NULL,
  CALENDAR      BYTEA        NOT NULL,
  PRIMARY KEY (SCHED_NAME, CALENDAR_NAME)
);


CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
(
  SCHED_NAME    VARCHAR(120) NOT NULL,
  TRIGGER_GROUP VARCHAR(200) NOT NULL,
  PRIMARY KEY (SCHED_NAME, TRIGGER_GROUP)
);

CREATE TABLE QRTZ_FIRED_TRIGGERS
(
  SCHED_NAME        VARCHAR(120) NOT NULL,
  ENTRY_ID          VARCHAR(95)  NOT NULL,
  TRIGGER_NAME      VARCHAR(200) NOT NULL,
  TRIGGER_GROUP     VARCHAR(200) NOT NULL,
  INSTANCE_NAME     VARCHAR(200) NOT NULL,
  FIRED_TIME        BIGINT       NOT NULL,
  SCHED_TIME        BIGINT       NOT NULL,
  PRIORITY          INTEGER      NOT NULL,
  STATE             VARCHAR(16)  NOT NULL,
  JOB_NAME          VARCHAR(200) NULL,
  JOB_GROUP         VARCHAR(200) NULL,
  IS_NONCONCURRENT  BOOL         NULL,
  REQUESTS_RECOVERY BOOL         NULL,
  PRIMARY KEY (SCHED_NAME, ENTRY_ID)
);

CREATE TABLE QRTZ_SCHEDULER_STATE
(
  SCHED_NAME        VARCHAR(120) NOT NULL,
  INSTANCE_NAME     VARCHAR(200) NOT NULL,
  LAST_CHECKIN_TIME BIGINT       NOT NULL,
  CHECKIN_INTERVAL  BIGINT       NOT NULL,
  PRIMARY KEY (SCHED_NAME, INSTANCE_NAME)
);

CREATE TABLE QRTZ_LOCKS
(
  SCHED_NAME VARCHAR(120) NOT NULL,
  LOCK_NAME  VARCHAR(40)  NOT NULL,
  PRIMARY KEY (SCHED_NAME, LOCK_NAME)
);

CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY
  ON QRTZ_JOB_DETAILS (SCHED_NAME, REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP
  ON QRTZ_JOB_DETAILS (SCHED_NAME, JOB_GROUP);

CREATE INDEX IDX_QRTZ_T_J
  ON QRTZ_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG
  ON QRTZ_TRIGGERS (SCHED_NAME, JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C
  ON QRTZ_TRIGGERS (SCHED_NAME, CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G
  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE
  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE
  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE
  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP, TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME
  ON QRTZ_TRIGGERS (SCHED_NAME, NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST
  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE
  ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE
  ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP
  ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_GROUP, TRIGGER_STATE);

CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME
  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY
  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME, REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G
  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG
  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G
  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG
  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
COMMIT;
4. 创建调度器工厂
@Configuration
public class SchedulerConfig {
    

    // 配置文件路径
    private static final String SERVICEX_QUARTZ_CONFIG_PATH = "/servicex-quartz.properties";

    // 控制器工厂类
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {
    
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setDataSource(dataSource);
        factory.setQuartzProperties(quartzProperties());
        factory.setStartupDelay(1);
        factory.setApplicationContextSchedulerContextKey("SERVICEX-APPLICATION-CONTEXT-KEY");
        factory.setOverwriteExistingJobs(true);
        factory.setAutoStartup(true);
        return factory;
    }

    @Bean
    @ConditionalOnResource(resources = SERVICEX_QUARTZ_CONFIG_PATH)
    Properties quartzProperties() {
    
        try {
    
            PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
            propertiesFactoryBean.setLocation(new ClassPathResource(SERVICEX_QUARTZ_CONFIG_PATH));
            propertiesFactoryBean.afterPropertiesSet();
            Properties properties = propertiesFactoryBean.getObject();
            return properties;
        } catch (IOException e) {
    
            System.out.println("QUARTZ相关的配置文件不存在.");
            e.printStackTrace();
        }
        return null;
    }
}
5. 封装任务
/**
 * 抽象JOB的封装
 * JOB表示一个任务, 也就是执行的具体的内容, 一个JOB可以被多个TRIGGER关联, 但是一个TRIGGER只能关联一个JOB.
 * @author ROCKY
 * @createTime 2022年07月04日
 */

@Slf4j
public abstract class AbstractQuartzJob implements Job {
    

    // 线程本地变量
    private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
    
        ServicexJob job = new ServicexJob();
        BeanUtils.copyProperties(context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES), job);
        try {
    
            before(context, job);
            if (job != null) {
    
                doExecute(context, job);
            }
            after(context, job, null);
        } catch (Exception e) {
    
            after(context, job, e);
            log.error("任务执行异常:", e);
        }
    }

    // 1. 执行前
    protected void before(JobExecutionContext context, ServicexJob job) {
    
        threadLocal.set(new Date());
    }

    // 2. 执行方法, 实际的子JOB重载该方法
    protected abstract void doExecute(JobExecutionContext context, ServicexJob job) throws Exception;

    // 3. 执行后
    protected void after(JobExecutionContext context, ServicexJob job, Exception e) {
    
        threadLocal.remove();
        // 质检完成后会做一些操作
        job.doSomeThings();
    }

}
6. 具体任务
/**
 * 不支持并发执行任务的JOB(禁止并发执行, 表示Quartz不能并发的执行同一个JOB的定义, 特指一个JOB类的多个实例)
 * @author ROCKY
 * @createTime 2022年07月04日
 */
@Slf4j
@DisallowConcurrentExecution
public class MyJobExecution extends AbstractQuartzJob {
    
    @Override
    protected void doExecute(JobExecutionContext context, ServicexJob job) throws Exception {
    
        // 真正的调用逻辑
        log.info("TO DO SOMETHING."+ job.getCronExpression() + "[" + job.getNextValidTime() + "]");
    }
}
7. 编写调度器服务
/**
 * 调度器服务
 * JobDetail:用于定义作业的实例
 * Trigger: 触发器, 执行给定作业计划的组件实例
 * Scheduler: 与调度程序交互的主要的API
 * CronScheduleBuilder:用于创建一个Scheduler的生成器
 * 何时触发, 通过Trigger来定义, 使用TriggerBuilder进行构建
 * 什么任务, 通过JobDetail来定义, 使用JobBuilder进行构建
 * 执行逻辑, 通过JOB中的doExecute方法的具体实现, 执行具体的内容
 *
 * @author ROCKY
 * @createTime 2022年07月04日
 */
public class ServicexScheduler {
    

    // 1. 创建/新增任务
    public static void register(Scheduler scheduler, ServicexJob job, Class<? extends Job> jobClass) throws SchedulerException {
    

        // 1. 构建任务信息
        String jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        // 2.1 构建JOB-DETAIL
        JobKey jobKey = getJobKey(jobId, jobGroup);
        TriggerKey triggerKey = getTriggerKey(jobId, jobGroup);
        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobKey).build();
        // 2.2 设置参数
        jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);

        // 3. 构建CRON调度器
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
        try {
    
            cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);
        } catch (Exception e) {
    
            e.printStackTrace();
        }

        // 4. 构建触发器
        // .startAt(), 用于指定开始时间
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
                .startAt(job.getStartTime())
                .withSchedule(cronScheduleBuilder).build();


        // 5. 判断是否存在该定时任务
        if (scheduler.checkExists(jobKey)) {
    
            // 防止创建时存在数据问题(先移除再创建)
            scheduler.deleteJob(jobKey);
        }
        // 6. 根据JOB-DETAIL和建触发器创建定时任务
        scheduler.scheduleJob(jobDetail, trigger);

        // 7. 如果JOB的状态是暂停的/禁用的, 需要暂定该任务
        if (!job.getStatus().equals(ScheduleConstants.Status.ENABLED.getValue())) {
    
            scheduler.pauseJob(jobKey);
        }

    }

    public static void register(Scheduler scheduler, ServicexJob job) throws SchedulerException {
    
        register(scheduler, job, MyJobExecution.class);
    }

    // 2. 暂停任务
    public static int pause(Scheduler scheduler, ServicexJob job) throws SchedulerException {
    
        String jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        JobKey jobKey = getJobKey(jobId, jobGroup);
        if (StringUtils.isNotEmpty(jobId) && StringUtils.isNotEmpty(jobGroup) && scheduler.checkExists(jobKey)) {
    
            scheduler.pauseJob(jobKey);
            return 1;
        }
        return -1;
    }


    // 3. 恢复任务
    public static int resume(Scheduler scheduler, ServicexJob job) throws SchedulerException {
    
        String jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        JobKey jobKey = getJobKey(jobId, jobGroup);
        if (StringUtils.isNotEmpty(jobId) && StringUtils.isNotEmpty(jobGroup) && scheduler.checkExists(jobKey)) {
    
            scheduler.resumeJob(jobKey);
            return 1;
        }
        return -1;
    }

    // 4. 删除任务
    public static int delete(Scheduler scheduler, ServicexJob job) throws SchedulerException {
    
        String jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        JobKey jobKey = getJobKey(jobId, jobGroup);
        if (StringUtils.isNotEmpty(jobId) && StringUtils.isNotEmpty(jobGroup) && scheduler.checkExists(jobKey)) {
    
            scheduler.deleteJob(jobKey);
            return 1;
        }
        return -1;
    }

    // 5. 运行任务
    public static void run(Scheduler scheduler, ServicexJob job) throws SchedulerException {
    
        String jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        JobDataMap dataMap = new JobDataMap();
        dataMap.put(ScheduleConstants.TASK_PROPERTIES, job);
        scheduler.triggerJob(getJobKey(jobId, jobGroup), dataMap);
    }

    // 6. 更新任务
    public static void update(Scheduler scheduler, ServicexJob job) throws SchedulerException {
    
        String jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        JobKey jobKey = getJobKey(jobId, jobGroup);
        if (StringUtils.isNotEmpty(jobId) && StringUtils.isNotEmpty(jobGroup) && scheduler.checkExists(jobKey)) {
    
            // 移除
            scheduler.deleteJob(jobKey);
        }
        // 新建
        register(scheduler, job);
    }

    // 6. 更新任务
    public static void update(Scheduler scheduler, ServicexJob job, Class<? extends Job> jobClass) throws SchedulerException {
    
        String jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        JobKey jobKey = getJobKey(jobId, jobGroup);

        if (StringUtils.isNotEmpty(jobId) && StringUtils.isNotEmpty(jobGroup) && scheduler.checkExists(jobKey)) {
    
            // 移除
            scheduler.deleteJob(jobKey);
        }
        // 新建
        register(scheduler, job, jobClass);
    }


    // 获取任务的键
    private static JobKey getJobKey(String jobId, String jobGroup) {
    
        return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME_PREFIX + jobId, jobGroup);
    }

    // 获取任务的键
    private static JobKey getJobKey(String taskName, String jobId, String jobGroup) {
    
        String jobName = (StringUtils.isNotEmpty(taskName) ? taskName : ScheduleConstants.TASK_CLASS_NAME_PREFIX) + jobId;
        return JobKey.jobKey(jobName, jobGroup);
    }

    // 构建任务触发器
    private static TriggerKey getTriggerKey(String jobId, String jobGroup) {
    
        return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME_PREFIX + jobId, jobGroup);
    }

    // 设置定时任务执行计划的失火策略
    private static CronScheduleBuilder handleCronScheduleMisfirePolicy(ServicexJob job, CronScheduleBuilder cb)
            throws Exception {
    
        switch (job.getMisfirePolicy()) {
    
            case ScheduleConstants.MISFIRE_DEFAULT:
                return cb;
            case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
                return cb.withMisfireHandlingInstructionIgnoreMisfires();
            case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
                return cb.withMisfireHandlingInstructionFireAndProceed();
            case ScheduleConstants.MISFIRE_DO_NOTHING:
                return cb.withMisfireHandlingInstructionDoNothing();
            default:
                return null;
        }
    }
}
8. 注册任务

在服务启动时注册所有的任务:

@Service
@Slf4j
public class ServicexQuartzServiceImpl implements IServicexQuartzService {
    

    @Autowired
    private ServicexQuartzMapperservicexQuartzMapper;
    
    @Autowired
    private Scheduler scheduler;

    @PostConstruct
    public void init() throws SchedulerException {
    
        scheduler.clear();
        List<ServicexJob> jobs = new LambdaQueryChainWrapper<>(servicexQuartzMapper).eq(ServicexJob::getRunType, RunType.AUTO.getValue()).list();
        for (ServicexJob job : jobs) {
    
            ServicexScheduler.register(scheduler, job);
        }
    }
    ...
}

其他文章

SpringBoot - 集成Quartz框架之CRON表达式
SpringBoot - 集成Quartz框架之Quartz简介(一)
SpringBoot - 集成Quartz框架之常用配置(二)
SpringBoot - 集成Quartz框架之具体步骤(三)
SpringBoot - 集成Quartz框架之独立数据源(四)
SpringBoot - 集成Quartz框架之常见问题(五)
SpringBoot - 集成Quartz框架之@DisallowConcurrentExecution注解详解(六)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/goodjava2007/article/details/126982771

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签