Java实现定时任务,使用Quartz调度器

Quartz 是一个功能强大、开源、且特性丰富的作业调度库。它几乎可以用在任何的 Java 应用程序中,从微小的独立应用到大型的商业系统。Quartz 允许开发者根据时间间隔或特定时间点来调度作业(任务)的执行。

1.核心概念

调度器(Scheduler):这是整个系统的控制中心,是 Quartz 的大脑。开发者通过 Scheduler 的API来与框架交互,用于安排、执行、暂停、删除作业等。

作业(Job):这是一个接口,你需要实现它来定义你想要执行的任务。你创建一个类,实现 org.quartz.Job 接口,并重写 execute(JobExecutionContext context) 方法。你的业务逻辑就写在这个方法里。

触发器(Trigger):它定义何时执行作业。一个Job可以被多个Trigger触发,一个Trigger只能关联一个Job。

JobDetail :它用于定义Job的实例,包含了Job实体类以及各种静态属性。

2.常见应用场景

报表生成:每天凌晨生成前一天的报表、用户行为报告等。

自动化任务:在非高峰时执行数据备份、缓存预热等重量级任务。

数据同步/清理:定时从A系统同步到B系统,或定时清理数据库中的过期日志、临时数据。

邮件/消息推送:定时向用户发送生日祝福、新闻简报、促销活动通知。

系统监控与检查:每隔一段时间检查系统健康情况、服务是否可用、磁盘空间是否不足等。

3.导入Quartz依赖

<!-- 版本号可能有更新,请查看最新版本 -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
</dependency>

4.需要执行的作业

方法内部写自己需要执行的业务逻辑。

@Slf4j
public class MyJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        log.info("Cron定时任务执行开始:" + new Date());
        log.info("Cron定时任务执行结束:" + new Date());
    }
}

5.使用触发器、调度器来执行作业

这里是根据 SysJob 表数据来决定每天的特定时间执行(数据只有一条)。

这里将时间改成了Cron表达式,如果想改成每周或者每月需要修改 getCronExpression 方法。

@Slf4j
public class DailyScheduledTask {

    // 获取调度器
    private static Scheduler scheduler = null;

    private static Map<Long, JobKey> map = new ConcurrentHashMap<>();

    public static void addCron(SysJob sysJob) {
        try {
            // 获取调度器
            scheduler = StdSchedulerFactory.getDefaultScheduler();
            // 定义任务
            JobDetail job = JobBuilder.newJob(MyJob.class)
                    .withIdentity("myJob", "group1")
                    .build();

            // 使用Cron表达式设置每天的特定时间点
            String cronExpression = getCronExpression(sysJob.getCronTime());

            // 定义触发器,使用Cron表达式
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("myTrigger", "group1")
                    .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                    .build();
            // 将任务和触发器注册到调度器
            scheduler.scheduleJob(job, trigger);
            log.info("addCron的trigger:"+ JSON.toJSONString(trigger.getJobKey()));

            map.put(sysJob.getId(),trigger.getJobKey());

            // 启动调度器
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    // 删除定时任务
    public static void removeCron(Long id) {
        try {
            if (scheduler != null) {
                if (CollectionUtils.isNotEmpty(map)) {
                    log.info("removeCron的trigger:"+ JSON.toJSONString(map.get(id)));
                    scheduler.deleteJob(map.get(id));
                }
            }
        }catch (SchedulerException e) {
            e.printStackTrace();
        }

    }

    // 使用Cron表达式设置每天的特定时间点
    private static String getCronExpression(Date executionTime) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("ss mm HH");
        return dateFormat.format(executionTime) + " * * ?";
    }
}

6.SysJob 表结构

public class SysJob {
    private Long id;    //主键

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date cronTime;     //定时时间

    private Integer status;    //状态:0-未启用,1-启用

    private Long createId;
    private Date createTime;
    private Long updateId;
    private Date updateTime;
}

7.使用(修改表数据时,删除任务重新添加,修改任务时间)

@PostMapping("/updateCron")
public Result<?> updateCron(@RequestBody SysJob sysJob) {
    // 删除原本的任务
    SysJob byId = sysJobService.getById(sysJob.getId());
    if (1 == byId.getStatus()) {
        DailyScheduledTask.removeCron(sysJob.getId());
    }
    sysJob.setUpdateId(ThreadCache.get().getUserId());
    sysJob.setUpdateTime(new Date());
    boolean update = sysJobService.update(sysJob, Wrappers.<SysJob>lambdaQuery().eq(SysJob::getId, sysJob.getId()));
    // 修改成功:重新设定新的任务
    if (update) {
        Integer status = sysJob.getStatus();
        if (1 == status) {
            DailyScheduledTask.addCron(sysJob,jobDTO);
        }
    }
    return Result.success("");
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值