springboot动态定时任务整合quartz

springboot 动态定时任务

springboot实现动态定时任务的方法有两种:

  1. 可以实现SchedulingConfigurer 接口(可以见springboot 动态定时任务
  2. 整合quartz(当前文章要说的)

springboot整合需要的依赖

springboot整合quartz需要导入的依赖如下

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

在类路径下新增配置文件quartz.properties

# scheduler名称
org.quartz.scheduler.instanceName = MyScheduler
# 线程池初始化数
org.quartz.threadPool.threadCount = 10
# 持久化规则,这里是持久化到内存,官方文档上有持久化到数据库的
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

或者在yml文件新增配置

spring:
  quartz:
    job-store-type: MEMORY
    schedulerName: MyScheduler

quartz相关的介绍

quartz中最重要的就是JobTrigger,可以理解为任务和触发器,任务------>触发器是一对多的关系,一个任务可以有多个触发器,触发器------>任务是一对一的关系,一个触发器只能对应一个任务

Job的构建

springboot中job构建的方式是继承QuartzJobBean类,QuartzJobBean类是springboot封装过的,也可以直接去实现job接口,job接口是quartz的,推荐是使用继承QuartzJobBean,代码如下

@Slf4j
public class ReportAutoJob extends QuartzJobBean {

    private String id;

    public void setId(String id) {
        this.id = id;
    }
	/**
     * 调度器执行的方法
     * @param jobExecutionContext
     * @throws JobExecutionException
     */
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        log.info("自动任务开始执行");
    }
}

Trigger相关的构建

直接使用TriggerBuilder类来构建 首先介绍触发器规则构建类 一共有四种:

  1. CalendarIntervalScheduleBuilder(相当于SimpleScheduleBuilder的升级版多支持了天周年月的间隔执行)
  2. CronScheduleBuilder(可以构建cron表达式)
  3. DailyTimeIntervalScheduleBuilder(支持复杂的构建 例如OnMondayThroughFriday方法从周一到周五,推荐自己测试一下)
  4. SimpleScheduleBuilder(简单的构建器支持配置执行次数,支持时分秒为单位的间隔执行)
 // 这里是间隔一分钟循环执行
SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.repeatMinutelyForever(1);
Trigger trigger = TriggerBuilder.newTrigger()
				// trigger名称和trigger分组名
                .withIdentity( "triggerListener",  "triggerListenerGroup")
                .withSchedule(simpleScheduleBuilder)
                .build();

JobDetail相关的构建

JobDetail相关的构建

// 创建JobDetail
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("reportAutoService", this);
jobDataMap.put("frequencyType", frequencyType);
JobDetail myJob = JobBuilder.newJob(ReportAutoJob.class)
		// 设置相关的参数值,在任务中可以直接获取到
        .usingJobData("id", id)
        .usingJobData(jobDataMap)
        .withIdentity(jobName + "job", jobName + "jobGroup")
        .build();
JobDataMap的介绍

JobDataMap可以给任务传参在job中可以获取到,一共有两种方式:

  1. set方法
  2. jobExecutionContext
public class ReportAutoJob extends QuartzJobBean {

    private String id;

    /**
     * 1.Quartz自动赋值
     * @param id
     */
    public void setId(String id) {
        this.id = id;
    }

    /**
     * 调度器执行的方法
     * @param jobExecutionContext
     * @throws JobExecutionException
     */
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        log.info("自动任务开始执行 id: {}",id);
        // 2.直接获取
        JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        ReportAutoService reportAutoService = (ReportAutoService);
    }
}

组合Trigger和Job构成一个完整的定时任务

使用SimpleScheduleBuilder构建一个完整定时任务

public void createListener(){
        // 规则构建器
        SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.repeatMinutelyForever(1);
        Trigger trigger = TriggerBuilder.newTrigger()
                // trigger名称和trigger分组名
                .withIdentity( "triggerListener",  "triggerListenerGroup")
                .withSchedule(simpleScheduleBuilder)
                .build();
		
        JobDetail myJobListener = JobBuilder.newJob(ReportTaskListening.class)
				// JobDetail 名称和JobDetail分组名
                .withIdentity("jobListener", "jobListenerGroup")
                .build();


        Scheduler scheduler = null;
        try {
        	// 获取默认的Scheduler(任务调度器)
            scheduler = StdSchedulerFactory.getDefaultScheduler();
            // 组合JobDetail和Trigger构成一个完整的定时任务
            scheduler.scheduleJob(myJobListener, trigger);
            // 将所有处于待机的任务置于开始状态(这里的开始状态不是立即执行任务,而是到达任务触发器指定的触发时间才会执行)
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

这里是我开发时写的创建方法可以参考

/**
     * 创建指定的定时任务
     * @param cron cron表达式
     * @param triggerName 调度器名称
     * @param jobName 任务名称
     * @param id 任务的id这里最好自动生成
     * @param frequencyType 任务的类型(按天,按月,按周)
     * @param frequencyDay 按天传的参数,隔多少天执行一次
     * @param startTime 任务的开始时间
     */
public void creteScheduler(String cron, String triggerName, String jobName, String id, Integer frequencyType,
                                    Integer frequencyDay, Date startTime) {
        Trigger trigger = null;
        Trigger triggerOne = null;
        // 如果是按天
        if (frequencyType.equals(ReportEnums.AutoEnums.DAY.getKey())) {
        	// 直接使用简单的构建器使用CalendarIntervalScheduleBuilder也一样的
            SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.repeatHourlyForever(24 * frequencyDay);
            
            trigger = TriggerBuilder.newTrigger()
            		// 设置任务开始时间
                    .startAt(startTime)
                    .withIdentity(triggerName + "trigger", triggerName + "triggerGroup")
                    .withSchedule(simpleScheduleBuilder)
                    .build();
        } else {
        	// 不是按天直接用cron表达式
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
            trigger = TriggerBuilder.newTrigger()
                    .startNow()
                    .withIdentity(triggerName + "trigger", triggerName + "triggerGroup")
                    .withSchedule(cronScheduleBuilder)
                    .build();
            if (System.currentTimeMillis() < startTime.getTime()) {
                triggerOne = TriggerBuilder.newTrigger()
                		// 设置任务开始时间
                        .startAt(startTime)
                        // 设置任务结束时间
                        .endAt(startTime)
                        // 可以直接在调度器上直接指定任务是那一个,参数分别是任务名称和任务分组名称 
                        .forJob(jobName + "job", jobName + "jobGroup")
                        .withIdentity(triggerName + "oneTrigger")
                        .build();
            }
        }
		// 创建JobDetail
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("reportAutoService", this);
        jobDataMap.put("frequencyType", frequencyType);
        JobDetail myJob = JobBuilder.newJob(ReportAutoJob.class)
        		// 设置相关的参数值,在任务中可以直接获取到
                .usingJobData("id", id)
                .usingJobData(jobDataMap)
                .withIdentity(jobName + "job", jobName + "jobGroup")
                .build();
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            // 1.注意第一次构建定时任务可以scheduleJob,但如果构架过了再使用会出现异常就是JobDetail已经注册过了
            scheduler.scheduleJob(myJob, trigger);
            // 不是按天执行
            if (!frequencyType.equals(ReportEnums.AutoEnums.DAY.getKey())&&System.currentTimeMillis() < startTime.getTime()) {
                scheduler.scheduleJob(triggerOne);
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

任务的恢复暂停和删除

	/**
     *  删除指定的任务
     * @param jobName
     * @param jobGroupName
     */
    @Override
    public void deleteJob(String jobName, String jobGroupName) {
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
            scheduler.deleteJob(jobKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 修改 一个job的 时间表达式
     *
     * @param triggerName
     * @param triggerGroupName
     * @param jobTime
     */
    @Override
    public void updateJob(String triggerName, String triggerGroupName, String jobTime) {
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                    .withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).build();
            // 重启触发器
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }


    /**
     * 暂停一个job
     *
     * @param jobName
     * @param jobGroupName
     */
    @Override
    public void pauseJob(String jobName, String jobGroupName) {
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 恢复一个job
     *
     * @param jobName
     * @param jobGroupName
     */
    @Override
    public void resumeJob(String jobName, String jobGroupName) {
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

获取定时任务列表,可以获取到定时任务相关的信息

public void getTasks() {
        List<Map<String, Object>> jobList = null;
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
            Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
            jobList = new ArrayList<Map<String, Object>>(16);
            log.info("任务数量:{}",jobKeys.size()-1);
            for (JobKey jobKey : jobKeys) {
                List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                for (Trigger trigger : triggers) {
                    Map<String, Object> map = new HashMap<>(16);
                    map.put("jobName", jobKey.getName());
                    map.put("jobGroupName", jobKey.getGroup());
                    map.put("description", "触发器:" + trigger.getKey());
                    Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                    map.put("jobStatus", triggerState.name());
                    if (trigger instanceof CronTrigger) {
                        CronTrigger cronTrigger = (CronTrigger) trigger;
                        String cronExpression = cronTrigger.getCronExpression();
                        CronExpression cron = new CronExpression(cronExpression);
                        Date now = new Date();
                        // 之前任务下次执行时间
                        String format = DateUtil.format(cron.getTimeAfter(now), "yyyy-MM-dd HH:mm:ss");
                        log.info("cron任务名称:{} 任务状态:{} 下次执行时间:{}",jobKey.getName().replace("job",""),triggerState.name(),format);
                        map.put("jobTime", cronExpression);
                    }
                    if (trigger instanceof SimpleTrigger) {
                        SimpleTrigger simpleTrigger = (SimpleTrigger) trigger;
                        if ("triggerListener".equals(simpleTrigger.getKey().getName())){
                            continue;
                        }
                        Date fireTimeAfter = simpleTrigger.getFireTimeAfter(new Date());
                        String format = DateUtil.format(fireTimeAfter, "yyyy-MM-dd HH:mm:ss");
                        log.info("simple任务名称:{} 任务状态:{} 下次执行时间:{}",jobKey.getName().replace("job",""),triggerState.name(),format);
                    }

                    jobList.add(map);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麦片王子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值