首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >springboot 之集成quartz

springboot 之集成quartz

作者头像
felixxue
发布2022-12-30 10:17:00
2370
发布2022-12-30 10:17:00
举报
文章被收录于专栏:xueflyxuefly

前言

一直没机会做spring生态圈的框架,公司选择的是一些小众的微服务,鉴于此考虑,丰富自己的技术栈,花了两天时间从网上各网站上学习了springboot一些基础知识。 本章只介绍springboot微服务集成quartz,用于项目中用到的一些定时任务,调度任务框架。

环境准备

  • IntelliJ IDEA
  • 前一章中搭建的微服务框架

开始集成

  1. pom.xml中增加依赖包

依赖包.png

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
  1. quartz的使用分为两种类型,一种为服务启动时定时执行任务,另一种为服务启动后,通过某些操作控制的任务(可以通过操作对其进行停止,删除,启动...) 2.1.1 先说第一种:

EnableScheduling.png 在入口类DemoApplication中启用调度任务:增加注解@EnableScheduling 2.1.2 在demo包下新建schedule包,用于存放调度任务相关类,在schedule包下新建TestSchedule类:

TestSchedule.png

package com.example.demo.schedule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 类功能描述:<br>
 * <ul>
 * <li>类功能描述1<br>
 * <li>类功能描述2<br>
 * <li>类功能描述3<br>
 * <li>#cron 的表达式:
 *(1)0 0 2 1 * ? *   表示在每月的1日的凌晨2点调整任务
 *
 *(2)0 15 10 ? * MON-FRI   表示周一到周五每天上午10:15执行作业
 *
 *(3)0 15 10 ? 6L 2002-2006   表示2002-2006年的每个月的最后一个星期五上午10:15执行作
 *
 *(4)0 0 10,14,16 * * ?   每天上午10点,下午2点,4点
 *
 *(5)0 0/30 9-17 * * ?   朝九晚五工作时间内每半小时
 *
 *(6)0 0 12 ? * WED    表示每个星期三中午12点
 *
 *(7)0 0 12 * * ?   每天中午12点触发
 *
 *(8)0 15 10 ? * *    每天上午10:15触发
 *
 *(9)0 15 10 * * ?     每天上午10:15触发
 *
 *(10)0 15 10 * * ? *    每天上午10:15触发
 *
 *(11)0 15 10 * * ? 2005    2005年的每天上午10:15触发
 *
 *(12)0 * 14 * * ?     在每天下午2点到下午2:59期间的每1分钟触发
 *
 *(13)0 0/5 14 * * ?    在每天下午2点到下午2:55期间的每5分钟触发
 *
 *(14)0 0/5 14,18 * * ?     在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
 *
 *(15)0 0-5 14 * * ?    在每天下午2点到下午2:05期间的每1分钟触发
 *
 *(16)0 10,44 14 ? 3 WED    每年三月的星期三的下午2:10和2:44触发
 *
 *(17)0 15 10 ? * MON-FRI    周一至周五的上午10:15触发
 *
 *(18)0 15 10 15 * ?    每月15日上午10:15触发
 *
 *(19)0 15 10 L * ?    每月最后一日的上午10:15触发
 *
 *(20)0 15 10 ? * 6L    每月的最后一个星期五上午10:15触发
 *
 *(21)0 15 10 ? * 6L 2002-2005   2002年至2005年的每月的最后一个星期五上午10:15触发
 *
 *(22)0 15 10 ? * 6#3   每月的第三个星期五上午10:15触发<br>
 * </ul>
 * 修改记录:<br>
 * <ul>
 * <li>修改记录描述1<br>
 * <li>修改记录描述2<br>
 * <li>修改记录描述3<br>
 * </ul>
 *
 * @author xuefl
 * @version 5.0 since 2019-12-19
 */
@Component
@Slf4j
public class TestSchedule {

    @Scheduled(fixedRate = 10 * 1000, initialDelay = 5000)  //采用间隔调度,每10秒执行一次
    public void runJoba(){ //定义一个执行的任务
        log.info("[*******MyTaskA -- 间隔调度 ******]"+
                new SimpleDateFormat("yyy-MM-dd HH:mm:ss.SSS").format(new Date()));
    }

    @Scheduled(cron = "*/10 * * * * ?")  //采用间隔调度,每10秒执行一次
    public void runJobb(){ //定义一个执行的任务
        log.info("[*******MyTaskB -- 间隔调度 ******]"+
                new SimpleDateFormat("yyy-MM-dd HH:mm:ss.SSS").format(new Date()));
    }

}

此类中包含两种定时方式的定时任务(1.每n秒执行一次定时任务,2.按照cron表达式执行任务),使用方法只需要在执行业务的方法前加@Scheduled注解即可,根据不同场景,使用适当的定时方式执行定时任务

2.2.1 在与DemoApplication同级的包下新建一个Schedule的配置类SchedulerAutoConfiguration,用于通过ScheduleFactory生成schedule实例:

SchedulerAutoConfiguration.png

package com.example.demo;
import org.quartz.Scheduler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import java.io.IOException;

/**
 * 类功能描述:<br>
 * <ul>
 * <li>类功能描述1<br>
 * <li>类功能描述2<br>
 * <li>类功能描述3<br>
 * </ul>
 * 修改记录:<br>
 * <ul>
 * <li>修改记录描述1<br>
 * <li>修改记录描述2<br>
 * <li>修改记录描述3<br>
 * </ul>
 *
 * @author xuefl
 * @version 5.0 since 2019-12-19
 */
@Configuration
public class SchedulerAutoConfiguration {

    //这个地方如果需要使用自定义的executor,可以在别的地方配置好,然后这里注入
    //@Autowired
    //private ThreadPoolTaskExecutor taskExecutor;


    @Bean(name="SchedulerFactory")
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setAutoStartup(true);
        //这里如果不配置任务池,它就会默认加载SimpleThreadPool
        //factory.setTaskExecutor();
        return factory;
    }

    @Bean(name="funnyScheduler")
    public Scheduler scheduler() throws IOException {
        return schedulerFactoryBean().getScheduler();
    }
}

此处定义的Bean funnyScheduler会被后续schedule对象操作类中注入,注入时,名称必须一致 2.2.2 在service包下新建JobScheduleService接口,定义对调度任务的操作抽象方法

JobScheduleService.png

package com.example.demo.service;
import java.util.Date;

/**
 * 类功能描述:<br>
 * <ul>
 * <li>类功能描述1<br>
 * <li>类功能描述2<br>
 * <li>类功能描述3<br>
 * </ul>
 * 修改记录:<br>
 * <ul>
 * <li>修改记录描述1<br>
 * <li>修改记录描述2<br>
 * <li>修改记录描述3<br>
 * </ul>
 *
 * @author xuefl
 * @version 5.0 since 2019-12-19
 */
public interface JobScheduleService {

    /**
     * 功能描述: 添加简单任务
     * 可以自定义一个任务信息对象,然后从信息对象中获取参数创建简单任务
     *
     * @param
     * @return:void
     * @since: v1.0
     * @Author:xf
     * @Date: 2019/3/15 17:00
     */
    void addSimpleJob(Class taskClass, String jobName, String jobGroup, Date startTime, Date endTime);

    /**
     * 功能描述: 添加定时任务
     * 可以自定义一个任务信息对象,然后从信息对象中获取参数创建定时任务
     *
     * @param
     * @return:void
     * @since: v1.0
     * @Author:xf
     * @Date: 2019/3/15 17:00
     */
    void addCronJob(Class taskClass, String jobName, String jobGroup, Date startTime, Date endTime, String cronExpression);

    /**
     * 功能描述: 修改任务Trigger,即修改任务的定时机制
     *
     * @param
     * @return:void
     * @since: v1.0
     * @Author:xf
     * @Date: 2019/3/15 17:00
     */
    void modifyJob(String jobName, String jobGroup, String cronExpression);

    /**
     * 功能描述: 暂停任务,只支持定时任务的暂停,不支持单次任务,单次任务需要interrupt
     *
     * @param
     * @return:void
     * @since: v1.0
     * @Author:xf
     * @Date: 2019/3/15 17:00
     */
    void pauseJob(String jobName, String jobGroup);

    /**
     * 功能描述: 从暂停状态中恢复定时任务运行
     *
     * @param
     * @return:void
     * @since: v1.0
     * @Author:xf
     * @Date: 2019/3/15 17:00
     */
    void resumeJob(String jobName, String jobGroup);

    /**
     * 功能描述: 删除任务
     *
     * @param
     * @return:void
     * @since: v1.0
     * @Author:xf
     * @Date: 2019/3/15 17:00
     */
    void deleteJob(String jobName, String jobGroup);

}

2.2.3 在service.impl包下新建JobScheduleService接口的实现类JobScheduleServiceImpl

JobScheduleServiceImpl.png

package com.example.demo.service.impl;
import com.example.demo.service.JobScheduleService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.util.Date;

/**
 * 类功能描述:<br>
 * <ul>
 * <li>类功能描述1<br>
 * <li>类功能描述2<br>
 * <li>类功能描述3<br>
 * </ul>
 * 修改记录:<br>
 * <ul>
 * <li>修改记录描述1<br>
 * <li>修改记录描述2<br>
 * <li>修改记录描述3<br>
 * </ul>
 *
 * @author xuefl
 * @version 5.0 since 2019-12-19
 */
@Service
@Slf4j
public class JobScheduleServiceImpl implements JobScheduleService {

    /**
     * 因为在配置中设定了这个bean的名称,这里就需要指定bean的名称,不然启动就会报错
     */
    @Autowired
    @Qualifier("funnyScheduler")
    private Scheduler scheduler;

    /**
     * 功能描述: 添加简单任务
     *
     * @param
     * @return:void
     * @since: v1.0
     * @Author:xf
     * @Date: 2019/3/15 17:00
     */
    @Override
    public void addSimpleJob(Class taskClass, String jobName, String jobGroup, Date startTime, Date endTime) {
        JobDetail jobDetail = JobBuilder.newJob(taskClass).withIdentity(jobName, jobGroup).build();
        SimpleTrigger simpleTrigger = TriggerBuilder.newTrigger()
                .withIdentity(jobName, jobGroup)
                .startAt(startTime)
                .endAt(endTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(3)
                        .withRepeatCount(5))
                .build();
        try {
            scheduler.scheduleJob(jobDetail, simpleTrigger);
        } catch (SchedulerException e) {
            log.error("addSimpleJob catch {}", e.getMessage());
        }
    }

    /**
     * 功能描述: 添加定时任务
     *
     * @param
     * @return:void
     * @since: v1.0
     * @Author:xf
     * @Date: 2019/3/15 17:00
     */
    @Override
    public void addCronJob(Class taskClass, String jobName, String jobGroup, Date startTime, Date endTime, String cronExpression) {
        JobDetail jobDetail = JobBuilder.newJob(taskClass).withIdentity(jobName, jobGroup).build();
        // 触发器

        try {
            CronTrigger trigger = new CronTriggerImpl(jobName, jobGroup, jobName, jobGroup, startTime, endTime, cronExpression);// 触发器名,触发器组
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException | ParseException e) {
            log.error("addCronJob catch {}", e.getMessage());
        }
    }

    /**
     * 功能描述: 修改任务Trigger,即修改任务的定时机制
     *
     * @param
     * @return:void
     * @since: v1.0
     * @Author:xf
     * @Date: 2019/3/15 17:00
     */
    @Override
    public void modifyJob(String jobName, String jobGroup, String cronExpression) {
        TriggerKey oldKey = new TriggerKey(jobName, jobGroup);
        //表达式调度构建器(即任务执行的时间)
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
        //按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().
                withIdentity(jobName, jobGroup).withSchedule(scheduleBuilder).build();
        try {
            scheduler.rescheduleJob(oldKey, trigger);
        } catch (SchedulerException e) {
            log.error("modifyJob catch {}", e.getMessage());
        }
    }

    /**
     * 功能描述: 暂停任务,只支持定时任务的暂停,不支持单次任务,单次任务需要interrupt
     *
     * @param
     * @return:void
     * @since: v1.0
     * @Author:xf
     * @Date: 2019/3/15 17:00
     */
    @Override
    public void pauseJob(String jobName, String jobGroup) {
        JobKey jobKey = new JobKey(jobName, jobGroup);
        try {
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            if (StringUtils.isEmpty(jobDetail)) {
                System.out.println("没有这个job");
            }
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            log.error("pauseJob catch {}", e.getMessage());
        }
    }

    /**
     * 功能描述: 从暂停状态中恢复定时任务运行
     *
     * @param
     * @return:void
     * @since: v1.0
     * @Author:xf
     * @Date: 2019/3/15 17:00
     */
    @Override
    public void resumeJob(String jobName, String jobGroup) {
        JobKey jobKey = new JobKey(jobName, jobGroup);
        try {
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            log.error("resumeJob catch {}", e.getMessage());
        }
    }

    /**
     * 功能描述: 删除任务
     *
     * @param
     * @return:void
     * @since: v1.0
     * @Author:xf
     * @Date: 2019/3/15 17:00
     */
    @Override
    public void deleteJob(String jobName, String jobGroup) {
        JobKey jobKey = new JobKey(jobName, jobGroup);
        try {
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            log.error("deleteJob catch {}", e.getMessage());
        }
    }
}

此类实现了JobScheduleService 接口定义的对调度任务各种操作的具体实现步骤,通过注入funnyScheduler来操作。 2.2.4 定义了对调度任务的操作类后,需要增加自己的调度任务业务实现类,也就是任务具体要干的事,需要实现quartz中的Job接口,并重写其execute方法,在其中增加自己的业务流程,在schedule包中新建job包,并在job包下新建SimpleJob类:

SimpleJob.png

package com.example.demo.schedule.job;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * 类功能描述:<br>
 * <ul>
 * <li>类功能描述1<br>
 * <li>类功能描述2<br>
 * <li>类功能描述3<br>
 * </ul>
 * 修改记录:<br>
 * <ul>
 * <li>修改记录描述1<br>
 * <li>修改记录描述2<br>
 * <li>修改记录描述3<br>
 * </ul>
 *
 * @author xuefl
 * @version 5.0 since 2019-12-19
 */
@Slf4j
public class SimpleJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        log.info("简单任务执行中");
    }
}

2.2.5 最后这个任务是怎么被调用的呢?其实在任何地方,业务执行过程中,rest接口中,都可以对这个任务进行CUD操作:

scheduleSimpleJob.png

package com.example.demo.controller;
import com.example.demo.schedule.job.SimpleJob;
import com.example.demo.service.JobScheduleService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Date;

/**
 * 类功能描述:<br>
 * <ul>
 * <li>类功能描述1<br>
 * <li>类功能描述2<br>
 * <li>类功能描述3<br>
 * </ul>
 * 修改记录:<br>
 * <ul>
 * <li>修改记录描述1<br>
 * <li>修改记录描述2<br>
 * <li>修改记录描述3<br>
 * </ul>
 *
 * @author xuefl
 * @version 5.0 since 2019-12-18
 */
@RestController
@Api(value = "SwaggerValue", tags={"SwaggerController"},description = "swagger应用",  produces = MediaType.APPLICATION_JSON_VALUE)
public class SimpleController {
    @Resource
    private JobScheduleService jobScheduleService;

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    @ApiOperation(value="hello",httpMethod = "GET",notes="hello",produces = MediaType.APPLICATION_JSON_VALUE)
    public String sayHello() {
        return "hello world";
    }

    @RequestMapping(value = "/scheduleSimpleJob", method = RequestMethod.POST)
    @ApiOperation(value="scheduleSimpleJob",httpMethod = "POST",notes="scheduleSimpleJob",produces = MediaType.APPLICATION_JSON_VALUE)
    public void scheduleSimpleJob() {
        jobScheduleService.addSimpleJob(SimpleJob.class,
                "simpleJob", "simpleJob", new Date(), null);
    }

}

注入jobScheduleService对象后 增加一个接口/scheduleSimpleJob,增加其实现业务方法,通过jobScheduleService对象对调度任务进行管理,此处只以addSimpleJob为例,其他方法大家可以增加rest接口以测试

  1. 启动后运行日志如下

调度任务线程池实例化.png

第一种定时任务运行日志.png

第二种调度任务,接口调用后运行日志.png

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-01-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 环境准备
  • 开始集成
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档