Skip to content

huxuehao/quartzd

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

1. 导读

Quartz 是一个开源的作业调度框架,它产生的主要目的是为了解决企业级应用中复杂的任务调度问题。 在实际的业务场景中,常常需要按照特定的时间规则(如每天凌晨执行数据备份、每月初生成报表等)来执行各种任务,手动管理这些任务的调度不仅繁琐且容易出错。 Quartz 提供了一种灵活、可靠的方式来定义和管理这些任务的执行时间和顺序,使得开发者可以将更多的精力放在业务逻辑的实现上,而不是任务调度的细节。

Quartz 在“灵活性”、“可靠性” 和 “扩展性” 上有着优势,但是其在持久化方面的较为复杂,涉及的数据库表较多,对于一些轻量级的场景并不是很适合,本项目将提供一个超轻量的持久化方案、支持动态调用,并对 Quartz 的核心组件(Scheduler、Job、Trigger、JobDetial)进行了二次链式封装,降低了调度任务编写配置的复杂度。下面我们将以 “Quartzd” 来代指该项目。

一定要看这个demo类:src/main/java/com/quartzd/demo/DemoQuartzJob.java

2. 如何编写作业调度

Quartzd 中开发者编写作业调度开发者只需继承 QuartzJob 类并实现 doJob() 方法即可。

// 任务执行逻辑
public class DemoQuartzJob extends QuartzJob {
    @Override
    public Object doJob(JobExecutionContext context) {
        return "DemoQuartzJob 执行完成";
    }
}

3. 如何启动作业调度

结合上下两个方案,我们可以看出,相比于使用 Quartz 和核心组件创建任务实例要简便的多的多。在 Quartzd 中我们通过 QuartzConfigFactory 去构建出 QuartzConfig(调度配置),基于 QuartzClient 去创建任务任务实例即可。

public static void main(String[] args) {
     // 配置
     QuartzConfig jobConfig = new QuartzConfigFactory()
        .identity("12345678987654")
        .setJobClass(DemoQuartzJob.class)
        .cron("*/10 * * * * ?")
        .build();
        
     // 启动
     new QuartzClient().create(jobConfig);
 }

4. 如何持久化任务调度

通过 “如何启动作业调度” 我演示了如何启动作业调度,但是在实际的使用中,我们并不会如此创建,在 Quartzd 中提供了操作的 web api,如下:

@RestController
@RequestMapping("/job")
public class JobController {
    private final QuartzClient quartzClient;
    private final QuartzInfoService quartzInfoService;

    public JobController(QuartzClient quartzClient, QuartzInfoService quartzInfoService) {
        this.quartzClient = quartzClient;
        this.quartzInfoService = quartzInfoService;
    }

    @PostMapping("/add")
    public Object add(@RequestBody JobInfo jobInfo) {
        jobInfo.setId(Func.uuid());
        return quartzInfoService.save(jobInfo);
    }

    @PostMapping("/update")
    public Object update(@RequestBody JobInfo jobInfo) {
        JobInfo job = quartzInfoService.getById(jobInfo.getId());
        if (job == null) {
            throw new RuntimeException("任务实例不存在");
        }
        if (job.getStatus() == 1) {
            throw new RuntimeException("任务实例运行中,请先关闭实例");
        }
        return quartzInfoService.updateById(jobInfo);
    }

    @GetMapping("/updateCron")
    public Object updateCron(@RequestParam String id, @RequestParam String cron) {
        JobInfo job = quartzInfoService.getById(id);
        if (job == null) {
            throw new RuntimeException("任务实例不存在");
        }
        if (job.getStatus() == 1) {
            throw new RuntimeException("任务实例运行中,请先关闭实例");
        }
        if (cron.equals(job.getCron())) {
            return true;
        }
        job.setCron(cron);
        return quartzInfoService.updateById(job);
    }

    @GetMapping("/delete")
    public Object delete(@RequestParam String id) throws ClassNotFoundException {
        JobInfo jobInfo = quartzInfoService.getById(id);
        if (jobInfo == null) {
            return true;
        }
        if (jobInfo.getStatus() == 1) {
            quartzClient.remove(JobInit.buildConfig(jobInfo));
        }

        return quartzInfoService.removeById(id);
    }

    @GetMapping("/start")
    public Object start(@RequestParam String id) throws ClassNotFoundException {
        JobInfo jobInfo = quartzInfoService.getById(id);
        if (jobInfo == null) {
            throw new RuntimeException("任务实例不存在");
        }
        if (jobInfo.getStatus() == 1) {
           return true;
        }
        quartzClient.create(JobInit.buildConfig(jobInfo));
        return true;
    }

    @GetMapping("/stop")
    public Object stop(@RequestParam String id) throws ClassNotFoundException {
        JobInfo jobInfo = quartzInfoService.getById(id);
        if (jobInfo == null) {
            throw new RuntimeException("任务实例不存在");
        }
        if (jobInfo.getStatus() == 0) {
            return true;
        }
        quartzClient.remove(JobInit.buildConfig(jobInfo));
        return true;
    }
}

Quartzd 并为提供前端界面,需要开发者自行设计。

5. 表结构说明

CREATE TABLE `quartz_job_info` (
   `id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '任务身份唯一标识',
   `cron` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'cron',
   `job_class` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'job类路径',
   `data_map` text COLLATE utf8mb4_general_ci COMMENT '执行参数',
   `last_time` datetime DEFAULT NULL COMMENT '最新时间',
   `status` int DEFAULT NULL COMMENT '状态(0停止 1启动)',
   PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='quartz定时任务状态';

id : 主键,默认使用UUID。 cron:作业调度的Cron。 job_class:继承了 QuartzJob 的类的全类名。 data_map:数据格式为 JSON 字符串,作为执行方法中的变量去使用。

6. 核心类说明

config.core.com.hxh.quartzd.QuartzConfigFactoryQuartzd 中的一个核心类,其目的是创建 QuartzConfig,在 Quartzd 中,任务是基于 QuartzConfig 创建的。

# 下面是QuartzConfigFactory的完整使用

QuartzConfig config= new QuartzConfigFactory()
     // 设置唯一标识
     .identity("12345678987654") 
     // 设置自定义doJob类
     .setJobClass(DemoQuartzJob.class)
      // 可以再自定义job中取到在此传递的值,value使用json字符串
     .putDataMap(JobConst.DATA_MAP_KEY, "{code: \"12345678765\"}")
     // 设置cron表达式,也可以使用once()标识执行一次
     .cron("*/10 * * * * ?") 
     // 构建config
     .build(); 

client.core.com.hxh.quartzd.QuartzClientQuartzd 中另一个核心类,其作用是提供操作作业调度的 API,例如:创建、移除、更新、安全 / 强制执行一次

QuartzConfig config = ...

# 创建
quartzClient.create(config);

# 移除
quartzClient.remove(config);

# 更新
config.setCron("*/15 * * * * ?");
quartzClient.updateCron(config);

# 安全执行一次
quartzClient.createOnce(config, false);


# 强制执行一次
quartzClient.createOnce(config, true);

About

quartzd是基于quartz封装的动态作业调度,简化操作API,支持任务持久化和动态控制。

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages