springboot集成quartz(集群)实现定时任务(每天定时执行)

接上篇:springboot集成quartz(集群)实现任务定时/立即执行,整理好基础配置。
【需求描述】
每天凌晨两点定时执行该定时任务。
【实现方案】

package com.zz.aa.config;

import com.zz.aa.quartz.job.AutomatedExectionJob;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.apache.commons.lang3.ObjectUtils;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;

/**
 * @author 
 * @date 2023/6/1
 * @Description
 */
@Configuration
@ConfigurationProperties(prefix = "zz.schedule")
@Data
public class ScheduleQuartzJobConfig {

    @ApiModelProperty("定时任务,默认每天凌晨两点")
    private String quartzCron = "0 0 2 * * ?";

    @Autowired
    private QuartzConfig quartzConfig;

    @Bean
    public Trigger quartzJobTrigger() throws SchedulerException, IOException {
        String name = "schedule_task_name";
        JobKey jobKey = JobKey.jobKey(name, "job_group_name");
        JobDetail jobDetail = JobBuilder.newJob(AutomatedExectionJob.class)
                .withIdentity(jobKey)
                .storeDurably()
                .requestRecovery()
                .build();
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartzCron ).withMisfireHandlingInstructionDoNothing();
        //创建触发器
        TriggerKey triggerKey = TriggerKey.triggerKey(name, "trigger_group_name");
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .forJob(jobDetail)
                .withIdentity(triggerKey)
                .withSchedule(cronScheduleBuilder)
                .build();
        //创建调度器,粘合工作和触发器
        Scheduler scheduler = quartzConfig.scheduler();
        CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        // 已有该定时任务则更新,无则创建
        if (ObjectUtils.isNotEmpty(cronTrigger)) {
            //根据新的执行器重新关联触发器
            cronTrigger = cronTrigger
                    .getTriggerBuilder()
                    .withIdentity(triggerKey)
                    .withSchedule(cronScheduleBuilder)
                    .build();
            //重置对应的job
            scheduler.rescheduleJob(triggerKey, cronTrigger);
        } else {
            scheduler.scheduleJob(jobDetail, trigger);
        }
        //启动调度器
        if (!scheduler.isShutdown()) {
            scheduler.start();
        }
        return trigger;
    }
}

job类:

package com.zz.aa.quartz.job;

import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * @author 
 * @date 2023/5/31
 * @Description 定时任务
 */
@DisallowConcurrentExecution
@Slf4j
@Component
public class AutomatedExectionJob extends QuartzJobBean {

    @Autowired
    private ApplicationContext applicationContext;

    private static XxxService xxService;

    // 如果有其他业务类引入,就必须这样定义声明,否则传入对象会是null
    @PostConstruct
    public void initConstruct() {
        AutomatedExectionJob.apicHandlerManager = applicationContext.getBean(XxxService.class);
    }

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 调用业务逻辑类的该定时任务具体的业务逻辑方法
        xxService.scheduleTask();
    }
}

拓展:

  • @DisallowConcurrentExecution注解,禁止任务并发执行;定时任务是串行的

  • @DisallowConcurrentExecution注解:Quartz定时任务默认都是并发执行的,不会等待上一次任务执行完毕,只要间隔时间到就会执行,这样往往会导致我们执行的数据不正确。所以在job类上加上这个注解,可以保证同一个Job实现类中的同一个任务不能并发,其他的实现类任务不受影响

    consul作为配置中心,通过@Value注入的属性,修改consul的配置后,属性不能立即生效,需要服务重启。而通过@ConfigurationProperties注入的属性,修改consul的配置后,属性会立即生效,所以建议如果需要动态生效的配置,最好使用@ConfigurationProperties进行属性的注入。

@DisallowConcurrentExecution注解是Quartz调度框架中的一个注解,用于指示一个Job类在同一时间只能被一个线程执行。Quartz是一个功能强大的开源任务调度库,用于在Java应用程序中执行计划任务。

当一个Job类被标记为@DisallowConcurrentExecution时,Quartz调度器在执行该Job时会检查该Job是否已经在其他线程中执行。如果是,则等待上一个任务完成后再执行新的任务。

这个注解的作用是确保同一时间只有一个实例的Job在执行,避免并发执行可能导致的问题。例如,如果一个Job涉及对共享资源的修改,同时多个线程并发执行该Job可能会导致数据不一致或竞态条件等问题。

要使用@DisallowConcurrentExecution注解,需要满足以下条件:

  1. 在Job类上添加@DisallowConcurrentExecution注解。
  2. 配置Quartz调度器以使用注解驱动的方式创建和调度Job。

以下是一个示例:

import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

@DisallowConcurrentExecution
public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 在这里编写任务逻辑
    }
}

在上面的示例中,MyJob类被标记为@DisallowConcurrentExecution,表示在同一时间只能有一个线程执行该Job。当Quartz调度器执行该Job时,会确保同一时间只有一个线程在执行execute方法。

使用@DisallowConcurrentExecution注解可以保证任务的串行执行,确保在同一时间只有一个实例的Job在执行,从而避免潜在的并发问题。

你可能感兴趣的:(软件开发,spring,boot,后端,java)