在Springboot项目中使用Quartz执行定时任务

2023-12-19

所使用的jar包

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

使用默认单机模式。单机模式中,Job 和Trigger是存放在内存中Map,通过源码可以看出 quartz-2.3.0.sources.jar!/org/quartz/simpl/RAMJobStore.java

    protected HashMap<JobKey, JobWrapper> jobsByKey = new HashMap<JobKey, JobWrapper>(1000);

    protected HashMap<TriggerKey, TriggerWrapper> triggersByKey = new HashMap<TriggerKey, TriggerWrapper>(1000);

    protected HashMap<String, HashMap<JobKey, JobWrapper>> jobsByGroup = new HashMap<String, HashMap<JobKey, JobWrapper>>(25);

    protected HashMap<String, HashMap<TriggerKey, TriggerWrapper>> triggersByGroup = new HashMap<String, HashMap<TriggerKey, TriggerWrapper>>(25);

    protected TreeSet<TriggerWrapper> timeTriggers = new TreeSet<TriggerWrapper>(new TriggerWrapperComparator());

    protected HashMap<String, Calendar> calendarsByName = new HashMap<String, Calendar>(25);

    protected Map<JobKey, List<TriggerWrapper>> triggersByJob = new HashMap<JobKey, List<TriggerWrapper>>(1000);

    protected final Object lock = new Object();

    protected HashSet<String> pausedTriggerGroups = new HashSet<String>();

    protected HashSet<String> pausedJobGroups = new HashSet<String>();

    protected HashSet<JobKey> blockedJobs = new HashSet<JobKey>();

官网支持集群是把这些数据存放在mysql, 也有人改成使用 redis存放这些数据

结合Springboot

注意此处Job要扩展QuartzJobBean , 只有这样才能使用@Autowired进来的其它service实例,否则要显式地new 一个相应service的实例

@Slf4j
@Component
@DisallowConcurrentExecution
public class MyJob extends QuartzJobBean {

    @Autowired
    ApplicationService applicationService;


    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        log.info("触发MyJob=========");

        applicationService.doSomething();

        Trigger trigger = jobExecutionContext.getTrigger();
        log.info("触发MyJob==========the trigger time : {}, 当前时间: {}",
                trigger.getStartTime(), new Date());

    }
}

设置Schedule

public interface QuartzService {

    void startSchedule ();

    void deployMySchedule (Myparams params) throws SchedulerException, ParseException;

}

定义trigger并设置Schedule


@Slf4j
@Service
public class QuartzServiceImpl implements QuartzService {


    private final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.ENGLISH);

    private final String myJobName = "MyJobName";
    private final String QUARTZ_JOB_GROUP_SUFFIX = "Group";


    @Autowired
    private Scheduler scheduler;

    @Override
    public void deployMySchedule (MyParams params) throws SchedulerException, ParseException {

        if (checkMyJobExists(params)) {
            log.warn("已存在{}的任务", params.getJobName());
            updateMyJobTrigger(params);
        } else {
            log.info("不存在{}的任务, 添加任务", params.getJobName());
            arrangeNewMyJobSchedule(params);
        }
    }


    @Override
    public void startSchedule ()  {

        try {
            scheduler.start();
        } catch (SchedulerException e) {
            log.error("Quartz 启动Schedule 出现异常 ==== ", e);
        }
    }

    /**
     * {
     *     "myJobName": "my.customized.job.name",
     *     "triggerTime": "2023-09-21 23:23:23"
     * }
     * @param params
     * @throws SchedulerException
     */

    private void arrangeNewMyJobSchedule (MyParams params) throws SchedulerException, ParseException {

        String jobName = params.getMyJobName();
        String jobGroup = params.getMyJobName()+QUARTZ_JOB_GROUP_SUFFIX;
        String triggerTime = params.getTriggerTime();

        // TODO change triggerTime to Date()
        Date date = formatter.parse(triggerTime);
        log.info("{} 添加定时任务", params.getMyJobName());

        JobKey theJobKey = jobKey(jobName, jobGroup);

        JobDetail job = JobBuilder.newJob(MyJob.class)
                .usingJobData("myJobName", params.getMyJobName())
                .withIdentity(theJobKey)
                .build();

        // Simple trigger without repeating
        // withMisfireHandlingInstructionNextWithRemainingCount()
        // Does nothing, misfired execution is ignored and there is no next execution.
        // Use this instruction when you want to completely discard the misfired execution.
        // Example scenario: the trigger was suppose to start recording of a program in TV.
        // There is no point of starting recording when the trigger misfired and is already 2 hours late.
        // Discarded but job not removed
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey(jobName, jobGroup))
                .startAt(date)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withMisfireHandlingInstructionNextWithRemainingCount())
                .build();

        // 使用触发器调度任务的执行
        scheduler.scheduleJob(job, trigger);
        log.info("{} 设置任务触发时间为: {}, 配置触发器", params.getMyJobName(), triggerTime);

        log.info("schedule: scheduleName {}, scheduleInstanceId {} ", scheduler.getSchedulerName(),
                scheduler.getSchedulerInstanceId());

    }

    private void updateMyJobTrigger (MyParams params) throws SchedulerException, ParseException {
        String jobName = params.getMyJobName();
        String jobGroup = params.getMyJobName()+"Group";
        String triggerTime = params.getTriggerTime();

        updateJobTrigger(jobName, jobGroup, triggerTime);
    }

    private boolean checkMyJobExists (MyParams params) throws SchedulerException {
        String jobName = params.getMyJobName();
        String jobGroup = params.getMyJobName()+QUARTZ_JOB_GROUP_SUFFIX;
        JobKey jobKey = new JobKey(jobName, jobGroup);
        return scheduler.checkExists(jobKey);
    }


    private void updateJobTrigger (String jobName, String jobGroup, String triggerTime) throws ParseException {

        // TODO change triggerTime to Date()
        Date date = formatter.parse(triggerTime);

        try {
            TriggerKey triggerKey = triggerKey(jobName, jobGroup);
            SimpleTrigger oldTrigger = (SimpleTrigger) scheduler.getTrigger(triggerKey);

            // Simple trigger without repeating
            // withMisfireHandlingInstructionNextWithRemainingCount()
            // 如果给的时间小于当前时间, 只重新配置触发器, 并不触发, 同时 jobdetail 也没有删除
            Trigger newTrigger = oldTrigger.getTriggerBuilder().withIdentity(triggerKey)
                    .withSchedule(simpleSchedule()
                            .withMisfireHandlingInstructionNextWithRemainingCount())
                    .startAt(date)
                    .build();
            // 重启触发器
            scheduler.rescheduleJob(oldTrigger.getKey(), newTrigger);
            log.info("Job {} 任务触发时间更新为: {}, 重新配置触发器", jobName, triggerTime);

        } catch (SchedulerException e) {
            e.printStackTrace();
        }

    }
}

在项目启动时加载schedule

@Slf4j
@Component
public class MyQuartzScheduleStart {

    @Autowired
    QuartzService quartzService;

    @PostConstruct
    public void init() {
        log.info("Quartz 调度任务开始 =====");
        quartzService.startSchedule();
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在Springboot项目中使用Quartz执行定时任务 的相关文章

随机推荐

  • 搭建电子商务网站建设步骤

    随着目前电子商务网站开发技术的迭代 电商网站的交互设计得到了很大程度的提升 可以认为现在的新型的商城平台都呈现出交互效果 那么电子商务网站建设步骤包括什么呢 电子商务网站建设第一步 网站的规划与设计 电子商务网站算是一个比较复杂的系统 电商
  • 如何在Linux系统中删除文件或目录?

    Linux作为流行的操作系统之一 许多公司和组织都在使用Linux来运行其关键业务和服务 例如谷歌 亚马逊和Facebook等 在Linux中 删除文件和目录是基本操作 那么该如何实现这一功能呢 以下是详细的内容 一 使用命令行删除文件 如
  • 渗透测试报告怎么写?

    1 准备好渗透测试记录 测试记录是执行过程的日志 在每日测试工作结束后 应将当日的成果做成记录 虽然内容不必太过细致 但测试的重点必须记录在案 拟检测的项目 使用的工具或方法 检测过程描述 检测结果说明 过程的重点截图 有结果的画面 2 撰
  • 什么是深度学习的无监督学习与有监督学习

    无监督学习 深度学习中的无监督学习方法是一种训练算法 它在没有标注输出的情况下从输入数据中学习模式和特征 这种方法的核心是探索和理解数据的内在结构和分布 而不是通过已知的输出来指导学习过程 无监督学习在深度学习领域有许多不同的形式和应用 以
  • binlog日志,二进制日志的简介

    binlog的bin就暴露了他是二进制的文件 你用vi或者vim是没办法读的 得用专门的方式 比如mysqlbinlog工具 那么binlog其实只要了解几点应该就足够了 Q 首先 binlog记录的是啥呢 A 记录的是数据库的修改过程 注
  • 2023_Spark_实验二十八:Flume部署及配置

    实验目的 熟悉掌握Flume部署及配置 实验方法 通过在集群中部署Flume 掌握Flume配置 实验步骤 一 Flume简介 Flume是一种分布式的 可靠的和可用的服务 用于有效地收集 聚合和移动大量日志数据 它有一个简单灵活的基于流数
  • 2023_Spark_实验二十九:Flume配置KafkaSink

    实验目的 掌握Flume采集数据发送到Kafka的方法 实验方法 通过配置Flume的KafkaSink采集数据到Kafka中 实验步骤 一 明确日志采集方式 一般Flume采集日志source有两种方式 1 Exec类型的Source 可
  • 线性连续控制系统

    线性连续控制系统 可以用线性微分方程表示 形式为 上式中 是被控制量 是系统的输入量 线性定常连续系统 当系数 和 常数时 称为定常系统 线性时变连续系统 当 和 随时间变化时 称为时变系统 线性定常连续系统按照输入量 的变化规律不同 又分
  • PyCharm中缓存有何作用?如何清理?

    在使用pycharm开发软件的过程中 我们经常会遇到卡顿 运行慢等问题 这时第一应对措施就是清理缓存 从而提高效率 那么pycharm如何清理缓存 以下是常用方法介绍 PyCharm缓存的作用 在使用PyCharm进行开发时 PyCharm
  • 推动行业未来的八个数字化转型趋势

    根据 Gartner 最新估计 在2023 年 已有40 的组织把虚拟体验与物理体验结合起来 以提高员工生产力和客户覆盖范围 而到 2024 年 工业企业将通过将自我管理技术与重新设计的运营流程相结合 将运营成本降低 30 到 2025 年
  • 低代码助力全栈开发

    目录 低代码功能展示 1 拖拽式 UI 组件 2 更快的开发速度 3 敏捷原型设计 4 与数据库集成 低代码开发工具正变得日益强大 它正不断弥合着前后端开发之间的差距 对于后端来说 基于低代码平台开发应用时 完全不用担心 前端的打包 部署
  • JavaOOP篇----第三篇

    系列文章目录 文章目录 系列文章目录 前言 一 标识符的命名规则 二 instanceof关键字的作用 三 什么是隐式转换 什么是显式转换 前言 前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住分享一下给大家 点击跳转到网
  • Linux中动态路由协议有哪些?

    Linux动态路由是一种在Linux操作系统中实现动态路由的机制 动态路由是指路由器能够根据网络的变化自动更新路由表 以实现更高效的数据传输 在Linux中 动态路由可以通过配置路由规则来实现 那么Linux中动态路由协议有哪些 以下是具体
  • kubernetes入门到进阶(2)

    被隔离的进程 一起来看看容器的本质 大家好 我们继续来一起学习k8s 在上一个章节里 我们初步了解了容器技术 在Linux虚拟机里安装了当前最流行的容器docker 还是用了docker ps docker run 等命令简单操作了容器 广
  • 【计算机图形学】PointNet文章的简单理解与运用,点云特征提取

    PointNet论文原文 PointNet Deep Learning on Point Sets for 3D Classification and Segmentation PointNet官方代码是使用tensorflow实现的 Po
  • 数据库学习日常案例20231218-oracle 19RAC hip远程注册服务到scan listener分析

    问题 用户一套Oracle19c RAC集群 出现一个奇怪的现象 通过SCAN IP访问的连接会话都集中在节点一实例 而且用户并没有做任何的节点服务访问去控制会话的连接节点 比如常见的通过集群的高可用服务去控制应用访问连接集中在同一节点 从
  • 渗透测试与安全测试主要区别是什么?

    在网络安全体系中 有很多专业术语 而且部分专业术语在名字上有很大的相似之处 因此很多小伙伴将它们混淆在一起 比如渗透测试和安全测试 这两个概念就经常被混淆在一起 那么什么是渗透测试和安全测试 有何区别 渗透测试是通过模拟恶意黑客的攻击方法
  • 转移mysql中的数据

    目录 1 mysqldump 2 将数据库中的数据转换为一个sql文件 3 执行sql文件 1 mysqldump 转移数据需要用到mysqldump 默认情况下mysqldump会自动被安装上 如果没有用不了 建议重新安装一下 参考 my
  • 4.docker镜像及相关命令

    目录 1 查看所有镜像 docker images 1 1 基本用法 1 2 docker images q 只显示所有镜像ID 1 3 docker images f 筛选条件 q 只显示符合条件的所有镜像ID 1 4 docker im
  • 在Springboot项目中使用Quartz执行定时任务

    所使用的jar包