美文网首页webSpringBoot极简教程 · Spring Boot Spring boot
SpringBoot 集成Quartz发布、修改、暂停、删除定时

SpringBoot 集成Quartz发布、修改、暂停、删除定时

作者: LssTechnology | 来源:发表于2019-03-28 21:40 被阅读228次

    前言

    >>>SpringBoot自带schedule

    SpringBoot本身支持表达式等多种定时任务,使用起来也很方便,但是如果使用复杂的任务操作时,SpringBoot自带的稍显不足,使用SpringBoot自带的定时任务, 只需要在程序启动的时候加上@EnableScheduling

    @Scheduled(cron="0/20 * * * * ?")
    public void task(){
          System.out.println("task - 20秒执行一次");
    }
    

    使用十分简单,本文不过多陈述

    >>>为什么使用Quartz

    多任务情况下,quartz更容易管理,可以实现动态配置 ,可随时删除和修改定时任务,方便使用

    1、SpringBoot集成Quartz
    项目目录:
    1.png

    由于一些quartz集成需要导入quartz自带的一些mysql库,使用起来稍显负复杂,本文采用自己创建任务库来管理简单的定时任务
    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>learn</artifactId>
            <groupId>com.lss</groupId>
            <version>1.0</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
        <properties>
            <quertz.version>2.2.1</quertz.version>
        </properties>
        <artifactId>quartz</artifactId>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
            <dependency>
                <groupId>org.quartz-scheduler</groupId>
                <artifactId>quartz</artifactId>
                <version>${quertz.version}</version>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>
    

    application.yml

    spring:
      datasource:
        url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf8
        username: root
        password: 12345678
        driverClassName: com.mysql.jdbc.Driver
      jpa:
        database: mysql
        show-sql: true
        hibernate:
          ddl-auto: update
          naming:
            physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
        database-platform: org.hibernate.dialect.MySQL5Dialect
      quartz:
        #相关属性配置
        properties:
          org:
            quartz:
              #          dataSource:
              #            default:
              #              driver: com.mysql.jdbc.Driver
              #              URL: jdbc:mysql://localhost:3306/jobconfig?useUnicode=true&characterEncoding=utf8
              #              user: root
              #              password: 12345678
              #              maxConnections: 5
              scheduler:
                instanceName: DefaultQuartzScheduler
                instanceId: AUTO
              jobStore:
                class: org.quartz.impl.jdbcjobstore.JobStoreTX
                driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
                tablePrefix: qrtz_
                isClustered: false
                clusterCheckinInterval: 10000
                useProperties: true
              threadPool:
                class: org.quartz.simpl.SimpleThreadPool
                threadCount: 10
                threadPriority: 5
                threadsInheritContextClassLoaderOfInitializingThread: true
    
        #数据库方式
        job-store-type: JDBC
        #初始化表结构
        jdbc:
          initialize-schema: NEVER
    
    2、项目配置
    2.1、新建ScheduleQuartzJob类,实现quartz的Job接口
    package com.lss.job;
    import lombok.extern.slf4j.Slf4j;
    import org.quartz.Job;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    
    @Slf4j
    public class ScheduleQuartzJob implements Job {
        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
            String group = context.getJobDetail().getJobDataMap().get("group").toString();
            String name = context.getJobDetail().getJobDataMap().get("name").toString();
            log.info("执行了task...group:{}, name:{}", group, name);
            // 可在此执行定时任务的具体业务
            // ...
        }
    }
    
    2.2、新建ScheduleJobPo类,对应数据库
    package com.lss.entity.po;
    import lombok.Data;
    import javax.persistence.*;
    
    @Data
    @Table(name = "tbl_schedule_job")
    @Entity
    public class ScheduleJobPo {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Integer id;
       
        // 任务group名称
        @Column(name = "group_name")
        private String groupName;
    
        // 任务job名称
        @Column(name = "job_name")
        private String jobName;
    
        // cron表达式
        private String cron;
    
        // 0 - 代表正在执行  1 - 已删除  2 - 暂停
        @Column(name = "status")
        private Integer status;
    
        @Column(name = "create_time")
        private Long createTime;
    
        @Column(name = "modified_time")
        private Long modifiedTime;
    }
    
    2.3、新建ScheduleJobDaoRepository类,调用数据库
    package com.lss.dao;
    import com.lss.entity.po.ScheduleJobPo;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
    import org.springframework.stereotype.Repository;
    import java.util.List;
    
    @Repository
    public interface ScheduleJobDaoRepository extends JpaRepository<ScheduleJobPo, Integer>, JpaSpecificationExecutor<ScheduleJobPo> {
        public ScheduleJobPo findByIdAndStatus(Integer id, Integer status);
    
        public List<ScheduleJobPo> findAllByStatus(Integer status);
    
        public List<ScheduleJobPo> findByGroupNameAndJobNameAndStatus(String groupName, String jobName, Integer status);
    
        public List<ScheduleJobPo> findAllByStatusInOrderByCreateTimeDesc(List<Integer> statusList);
    }
    
    2.4、新建ScheduleJobService类,业务实现层
    package com.lss.service;
    
    import com.lss.dao.ScheduleJobDaoRepository;
    import com.lss.entity.model.ScheduleJobModel;
    import com.lss.entity.po.ScheduleJobPo;
    import com.lss.job.ScheduleQuartzJob;
    import com.lss.util.DateUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.quartz.*;
    import org.quartz.impl.StdSchedulerFactory;
    import org.quartz.impl.matchers.GroupMatcher;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.util.ObjectUtils;
    import org.springframework.util.StringUtils;
    import javax.annotation.PostConstruct;
    import java.util.List;
    import java.util.Set;
    
    @Service
    @Slf4j
    public class ScheduleJobService {
    
        // 获取工厂类
        private StdSchedulerFactory sf = new StdSchedulerFactory();
    
        @Autowired
        private ScheduleJobDaoRepository scheduleJobDaoRepository;
    
        // 项目重启后,初始化原本已经运行的定时任务
        @PostConstruct
        public void init(){
            List<ScheduleJobPo> poList = scheduleJobDaoRepository.findAllByStatus(0);
            poList.forEach(po -> {
                startScheduleByInit(po);
            });
        }
    
        /**
         * 初始化时开启定时任务
         */
        private void startScheduleByInit(ScheduleJobPo po){
            try {
                Scheduler scheduler = sf.getScheduler();
                startJob(scheduler, po.getGroupName(), po.getJobName(), po.getCron());
                scheduler.start();
            }catch (Exception e){
                log.error("exception:{}", e);
            }
        }
    
        /**
         * 开启定时任务
         * @param model
         */
        public void startSchedule(ScheduleJobModel model) {
            if (StringUtils.isEmpty(model.getGroupName()) || StringUtils.isEmpty(model.getJobName()) || StringUtils.isEmpty(model.getCron())){
                throw new RuntimeException("参数不能为空");
            }
            List<ScheduleJobPo> poList = scheduleJobDaoRepository.findByGroupNameAndJobNameAndStatus(model.getGroupName(), model.getJobName(), 0);
            if (!ObjectUtils.isEmpty(poList)){
                throw new RuntimeException("group和job名称已存在");
            }
            try {
                Scheduler scheduler = sf.getScheduler();
                startJob(scheduler, model.getGroupName(), model.getJobName(), model.getCron());
                scheduler.start();
                ScheduleJobPo scheduleJobPo = new ScheduleJobPo();
                scheduleJobPo.setGroupName(model.getGroupName());
                scheduleJobPo.setJobName(model.getJobName());
                scheduleJobPo.setCron(model.getCron());
                scheduleJobPo.setStatus(0);
                scheduleJobPo.setCreateTime(DateUtil.getCurrentTimeStamp());
                scheduleJobPo.setModifiedTime(DateUtil.getCurrentTimeStamp());
                scheduleJobDaoRepository.save(scheduleJobPo);
            }catch (Exception e){
                log.error("exception:{}", e);
            }
    
        }
    
        /**
         * 更新定时任务
         * @param model
         */
        public void scheduleUpdateCorn(ScheduleJobModel model) {
            if (ObjectUtils.isEmpty(model.getId()) || ObjectUtils.isEmpty(model.getCron())){
                throw new RuntimeException("定时任务不存在");
            }
            try {
                ScheduleJobPo po = scheduleJobDaoRepository.findByIdAndStatus(model.getId(), 0);
                // 获取调度对象
                Scheduler scheduler = sf.getScheduler();
                // 获取触发器
                TriggerKey triggerKey = new TriggerKey(po.getJobName(), po.getGroupName());
                CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
                String oldTime = cronTrigger.getCronExpression();
                if (!oldTime.equalsIgnoreCase(model.getCron())) {
                    CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(model.getCron());
                    CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(po.getJobName(), po.getGroupName())
                            .withSchedule(cronScheduleBuilder).build();
                    // 更新定时任务
                    scheduler.rescheduleJob(triggerKey, trigger);
                    po.setCron(model.getCron());
                    // 更新数据库
                    scheduleJobDaoRepository.save(po);
                }
            }catch (Exception e){
                log.info("exception:{}", e);
            }
    
        }
        /**
         * 任务 - 暂停
         */
        public void schedulePause(ScheduleJobModel model) {
            if (ObjectUtils.isEmpty(model.getId())){
                throw new RuntimeException("定时任务不存在");
            }
            ScheduleJobPo po = scheduleJobDaoRepository.findByIdAndStatus(model.getId(), 0);
            if (ObjectUtils.isEmpty(po)){
                throw new RuntimeException("定时任务不存在");
            }
            try {
                Scheduler scheduler = sf.getScheduler();
                JobKey jobKey = new JobKey(po.getJobName(), po.getGroupName());
                JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                if (jobDetail == null)
                    return;
                scheduler.pauseJob(jobKey);
                po.setStatus(2);
                scheduleJobDaoRepository.save(po);
            }catch (Exception e){
                log.error("exception:{}", e);
            }
        }
        /**
         * 任务 - 恢复
         */
    
        public void scheduleResume(ScheduleJobModel model) {
            if (ObjectUtils.isEmpty(model.getId())){
                throw new RuntimeException("定时任务不存在");
            }
            ScheduleJobPo po = scheduleJobDaoRepository.findByIdAndStatus(model.getId(), 2);
            if (ObjectUtils.isEmpty(po)){
                throw new RuntimeException("定时任务不存在");
            }
            try {
                Scheduler scheduler = sf.getScheduler();
                JobKey jobKey = new JobKey(po.getJobName(), po.getGroupName());
                JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                if (jobDetail == null)
                    return;
                scheduler.resumeJob(jobKey);
                po.setStatus(0);
                scheduleJobDaoRepository.save(po);
            }catch (Exception e){
                log.error("exception:{}", e);
            }
        }
        /**
         * 任务 - 删除一个定时任务
         */
        public void scheduleDelete(ScheduleJobModel model) {
            if (ObjectUtils.isEmpty(model.getId())){
                throw new RuntimeException("定时任务不存在");
            }
            ScheduleJobPo po = scheduleJobDaoRepository.findByIdAndStatus(model.getId(), 0);
            if (ObjectUtils.isEmpty(po)){
                throw new RuntimeException("定时任务不存在");
            }
            try {
                Scheduler scheduler = sf.getScheduler();
                JobKey jobKey = new JobKey(po.getJobName(), po.getGroupName());
                JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                if (jobDetail == null)
                    return;
                scheduler.deleteJob(jobKey);
                po.setStatus(1);
                scheduleJobDaoRepository.save(po);
            }catch (Exception e){
                log.error("exception:{}", e);
            }
        }
    
        /**
         * 删除所有定时任务
         */
        public void scheduleDeleteAll() {
            try {
                Scheduler scheduler = sf.getScheduler();
                // 获取有所的组
                List<String> jobGroupNameList = scheduler.getJobGroupNames();
                for (String jobGroupName : jobGroupNameList) {
                    GroupMatcher<JobKey> jobKeyGroupMatcher = GroupMatcher.jobGroupEquals(jobGroupName);
                    Set<JobKey> jobKeySet = scheduler.getJobKeys(jobKeyGroupMatcher);
                    for (JobKey jobKey : jobKeySet) {
                        String jobName = jobKey.getName();
                        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                        if (jobDetail == null)
                            return;
                        scheduler.deleteJob(jobKey);
                        // 更新数据库
                        List<ScheduleJobPo> poList = scheduleJobDaoRepository.findByGroupNameAndJobNameAndStatus(jobGroupName, jobName, 0);
                        poList.forEach(po -> {
                            po.setStatus(1);
                            scheduleJobDaoRepository.save(po);
                        });
                        log.info("group:{}, job:{}", jobGroupName, jobName);
                    }
                }
            }catch (Exception e){
                log.error("exception:{}", e);
            }
        }
        // 开启任务
        private void startJob(Scheduler scheduler, String group, String name, String cron) throws SchedulerException {
            // 通过JobBuilder构建JobDetail实例,JobDetail规定只能是实现Job接口的实例
            // 在map中可传入自定义参数,在job中使用
            JobDataMap map = new JobDataMap();
            map.put("group", group);
            map.put("name", name);
            // JobDetail 是具体Job实例
            JobDetail jobDetail = JobBuilder.newJob(ScheduleQuartzJob.class).withIdentity(name, group)
                    .usingJobData(map)
                    .build();
            // 基于表达式构建触发器
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
            // CronTrigger表达式触发器 继承于Trigger
            // TriggerBuilder 用于构建触发器实例
            CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(name, group)
                    .withSchedule(cronScheduleBuilder).build();
            scheduler.scheduleJob(jobDetail, cronTrigger);
        }
    }
    
    2.5、新建ScheduleJobModel类,参数调用
    package com.lss.entity.model;
    
    import lombok.Data;
    
    @Data
    public class ScheduleJobModel {
    
        private Integer id;
    
        private String groupName;
    
        private String jobName;
    
        private String cron;
    }
    
    2.6、新建TestController类,暴露restful接口,实现接口调用
    package com.lss.controller;
    
    import com.lss.entity.model.ScheduleJobModel;
    import com.lss.service.ScheduleJobService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping(value = "/api")
    public class TestController {
    
        @Autowired
        private ScheduleJobService scheduleJobService;
    
        /**
         * 开启
         * @param model
         * @return
         */
        @PostMapping("start")
        public String startSchedule(@RequestBody ScheduleJobModel model){
            scheduleJobService.startSchedule(model);
            return "ok";
        }
    
        /**
         * 更新
         * @param model
         * @return
         */
        @PostMapping("update")
        public String scheduleUpdateCorn(@RequestBody ScheduleJobModel model){
            scheduleJobService.scheduleUpdateCorn(model);
            return "ok";
        }
    
        /**
         * 暂停
         * @param model
         * @return
         */
        @PostMapping("/pause")
        public String schedulePause(@RequestBody ScheduleJobModel model){
            scheduleJobService.schedulePause(model);
            return "ok";
        }
    
        /**
         * 恢复
         * @param model
         * @return
         */
        @PostMapping("/resume")
        public String scheduleResume(@RequestBody ScheduleJobModel model){
            scheduleJobService.scheduleResume(model);
            return "ok";
        }
    
        /**
         * 删除一个定时任务
         * @param model
         * @return
         */
        @PostMapping("/delete")
        public String scheduleDelete(@RequestBody ScheduleJobModel model){
            scheduleJobService.scheduleDelete(model);
            return "ok";
        }
    
        /**
         * 删除所有定时任务
         * @param model
         * @return
         */
        @PostMapping("deleteAll")
        public String scheduleDeleteAll(@RequestBody ScheduleJobModel model){
            scheduleJobService.scheduleDeleteAll();
            return "ok";
        }
    }
    
    2.7、新建DateUtil类,获取当前日期
    package com.lss.util;
    
    public class DateUtil {
        /**
         * 得到当前时间戳
         * @return
         */
        public static Long getCurrentTimeStamp() {
            long timeMillis = System.currentTimeMillis();
            return timeMillis;
        }
    }
    
    以上是该项目的所有配置
    3、启动项目
    3.1、调用 /api/start 接口

    curl -H "Content-Type:application/json" -X POST --data '{"groupName":"group","jobName":"job","cron":"0/5 * * * * ?"}' http://localhost:8080/api/start
    看控制台日志,发现每隔5秒调用一次定时服务

    2.png
    3.2、调用 /api/update 接口

    curl -H "Content-Type:application/json" -X POST --data '{"id":1, "cron":"0/8 * * * * ?"}' http://localhost:8080/api/update
    看控制台日志,发现每隔8秒调用一次定时服务

    3.png
    这个接口实现是先调用的数据库,然后去quartz中更新了该定时任务,也可直接传入groupName和jobName去quartz中查询出来对应的定时任务,更新后再去更新数据库
    后一种方法更好,实现也很容易实现,学习的朋友们可参照接口 /api/deleteAll 中的一些业务操作实现该业务,本文不在过多陈述
    3.3、调用 /api/pause 接口

    curl -H "Content-Type:application/json" -X POST --data '{"id":1}' http://localhost:8080/api/pause
    看控制台日志,发现定时任务已停止

    3.4、调用 /api/resume 接口

    curl -H "Content-Type:application/json" -X POST --data '{"id":1}' http://localhost:8080/api/resume
    看控制台日志,发现定时任务已恢复

    3.5、调用 /api/delete 接口

    curl -H "Content-Type:application/json" -X POST --data '{"id":1}' http://localhost:8080/api/delete
    发现定时任务已删除

    3.6、调用 /api/deleteAll 接口

    curl -H "Content-Type:application/json" -X POST --data '{}' http://localhost:8080/api/deleteAll
    此时删除所有的定时任务

    附录一些cron表达式,方便记忆
    cron表达式
    字段 允许值 允许的特殊字符
    0-59 , - * /
    0-59 , - * /
    小时 0-23 , - * /
    日期 1-31 , - * ? / L C #
    月份 1-12 或者 JAN-DEC , - * /
    星期 1-7 或者 SUN-SAT , - * ? / L C #
    (可选)留空 1970-2099 , - * /
    每个符号的意义

    * 表示所有值;
    ? 表示未说明的值,即不关心它为何值;
    - 表示一个指定的范围;
    , 表示附加一个可能值
    / 符号前表示开始时间,符号后表示每次递增的值;
    L("last") ("last") "L" 用在day-of-month字段意思是 "这个月最后一天";用在 day-of-week字段, 它简单意思是 "7" or "SAT"。 如果在day-of-week字段里和数字联合使用,它的意思就是 "这个月的最后一个星期几" – 例如: "6L" means "这个月的最后一个星期五". 当我们用“L”时,不指明一个列表值或者范围是很重要的,不然的话,我们会得到一些意想不到的结果。
    W("weekday") 只能用在day-of-month字段。用来描叙最接近指定天的工作日(周一到周五)。例如:在day-of-month字段用“15W”指“最接近这个 月第15天的工作日”,即如果这个月第15天是周六,那么触发器将会在这个月第14天即周五触发;如果这个月第15天是周日,那么触发器将会在这个月第 16天即周一触发;如果这个月第15天是周二,那么就在触发器这天触发。注意一点:这个用法只会在当前月计算值,不会越过当前月。“W”字符仅能在 day-of-month指明一天,不能是一个范围或列表。也可以用“LW”来指定这个月的最后一个工作日。
    # 只能用在day-of-week字段。用来指定这个月的第几个周几。例:在day-of-week字段用"6#3"指这个月第3个周五(6指周五,3指第3个)。如果指定的日期不存在,触发器就不会触发。
    C 指和calendar联系后计算过的值。例:在day-of-month 字段用“5C”指在这个月第5天或之后包括calendar的第一天;在day-of-week字段用“1C”指在这周日或之后包括calendar的第一天。

    示例
    表达式 含义
    */5 * * * * ? 每隔5秒执行一次
    0 */1 * * * ? 每隔1分钟执行一次
    0 0 5-15 * * ? 每天5-15点整点触发
    0 0/3 * * * ? 每三分钟触发一次
    0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发
    0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
    0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
    0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
    0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
    0 0 12 ? * WED 表示每个星期三中午12点
    0 0 17 ? * TUES,THUR,SAT 每周二、四、六下午五点
    0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发
    0 15 10 ? * MON-FRI 周一至周五的上午10:15触发
    0 0 23 L * ? 每月最后一天23点执行一次
    0 15 10 L * ? 每月最后一日的上午10:15触发
    0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发
    0 15 10 * * ? 2005 2005年的每天上午10:15触发
    0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发
    0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发
    30 * * * * ? 每半分钟触发任务
    30 10 * * * ? 每小时的10分30秒触发任务
    30 10 1 * * ? 每天1点10分30秒触发任务
    30 10 1 20 * ? 每月20号1点10分30秒触发任务
    30 10 1 20 10 ? * 每年10月20号1点10分30秒触发任务
    30 10 1 20 10 ? 2011 2011年10月20号1点10分30秒触发任务
    30 10 1 ? 10 * 2011 2011年10月每天1点10分30秒触发任务
    30 10 1 ? 10 SUN 2011 2011年10月每周日1点10分30秒触发任务
    15,30,45 * * * * ? 每15秒,30秒,45秒时触发任务
    15-45 * * * * ? 15到45秒内,每秒都触发任务
    15/5 * * * * ? 每分钟的每15秒开始触发,每隔5秒触发一次
    15-30/5 * * * * ? 每分钟的15秒到30秒之间开始触发,每隔5秒触发一次
    0 0/3 * * * ? 每小时的第0分0秒开始,每三分钟触发一次
    0 15 10 ? * MON-FRI 星期一到星期五的10点15分0秒触发任务
    0 15 10 L * ? 每个月最后一天的10点15分0秒触发任务
    0 15 10 LW * ? 每个月最后一个工作日的10点15分0秒触发任务
    0 15 10 ? * 5L 每个月最后一个星期四的10点15分0秒触发任务
    0 15 10 ? * 5#3 每个月第三周的星期四的10点15分0秒触发任务
    以上就是本文的所有内容,如有不对,欢迎指正,欢迎讨论

    相关文章

      网友评论

        本文标题:SpringBoot 集成Quartz发布、修改、暂停、删除定时

        本文链接:https://www.haomeiwen.com/subject/jpkcbqtx.html