quartz实现动态定时任务

我们在开发中经常需要定时任务,比如定期去更新一些信息到文档中整理,删除等操作,这些情况可以使用 @Scheduled定时任务的使用 实现,但是一旦启动服务无法修改(本身是在接口上进行定时任务)

那么我们就需要部署一个quartz的动态定时任务系统管理,实现对任务,以及信息的操作

quartz的动态定时任务的核心就是编写任务,配置触发器,再使用调度工厂去调度这个任务

加上依赖

<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>

先实现一下简单的功能如下

实现持续一个月,每天0点打印信息,先写任务信息

class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 在这里编写要执行的任务逻辑
        System.out.println("新的一天");

        // 如果需要在一个月后停止任务,你可以在这里检查时间并调用scheduler的shutdown方法来停止调度器
        if (isOneMonthElapsed()) {
            try {
                Scheduler scheduler = jobExecutionContext.getScheduler();
                scheduler.shutdown(true); // true 表示等待当前任务执行完毕再关闭
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    }

    // 判断是否已经过了一个月
    private boolean isOneMonthElapsed() {
        // 在这里根据业务逻辑判断是否已经过了一个月
        // 你可以根据需要自定义逻辑
        return false; // 这里示例返回false,你需要实现自己的逻辑
    }
}

之后是配置 

public class MyScheduler {
    public static void main(String[] args) throws SchedulerException {
        // 创建调度器工厂
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();

        // 开始调度器
        scheduler.start();

        // 创建一个JobDetail,定义要执行的任务
        JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
                .withIdentity("myJob", "group1")
                .build();

        // 创建一个每天0点触发的触发器
        Calendar startTime = Calendar.getInstance();
        startTime.set(Calendar.HOUR_OF_DAY, 0);
        startTime.set(Calendar.MINUTE, 0);
        startTime.set(Calendar.SECOND, 0);
        startTime.set(Calendar.MILLISECOND, 0);

        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("dailyTrigger", "group1")
                .startAt(startTime.getTime()) // 定义任务开始时间
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInHours(24)  // 每24小时执行一次
                        .repeatForever()) // 一直重复执行
                .endAt(getEndTime()) // 结束时间为一个月后
                .build();

        // 将任务和触发器注册到调度器
        scheduler.scheduleJob(jobDetail, trigger);
    }

    // 获取一个月后的时间
    private static Date getEndTime() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH, 1); // 增加一个月
        return calendar.getTime();
    }
}

接下来我会讲解各种对象的作用

job:实现这个抽象类只有一个execute,参数是调度(Schedlue)执行时会传入调度器对象进行关闭等

如下图 

841da1f1c2a54fe3935ef1cb0c7b8e4b.png

内部是一些需要定时的逻辑 5cdf59ebe976471890228642dfee6d95.png

到这里任务对象就创建好了

接下来就是使用quartz的调度实现动态定时执行这个任务了 

//创建调度器工厂
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
//创建调度器
Scheduler scheduler = schedulerFactory.getScheduler();

创建调度器工厂如下

adcdbb8ddda54e51b525678bbddec321.png

 使用JobBuilder构造器根据MyJob自己的定时任务类构造一个JobDetail对象

为什么不直接使用MyJob进行调度呢,应为JobBuilder每次都会创建一个对象进行调度,不是单例,不会造成线程安全问题

094b664f854648848b86139dc8e5f874.png

记得在withIdentity函数内设置任务名称,所属组

之后是创建触发器

a215976270ee406ba7199174bd05ae3b.png

触发器核心有四个参数

开始时间 startAt(startTime.getTime()) 
结束时间 endAt(getEndTime())
重复次数 repeatForever() 一直重复执行 直到结束时间
重复间隔 withIntervalInHours(24)

注意withIdentity这两个参数和上面没啥关系 

创建成功后进行绑定调度器

602c04c783ff49a9afa096af572835bd.png

这样就绑定调度器成功了 

启动和关闭调度器讲解

scheduler.start()
这个方法用于启动 Quartz 调度器,让它开始执行预定的任务
一旦调度器启动,它将按照已定义的触发器和作业来执行任务
调度器启动后,可以随时添加新的作业和触发器,它会根据已有的调度配置继续执行任务

scheduler.shutdown()
这个方法用于关闭 Quartz 调度器,停止任务的执行
调用 scheduler.shutdown() 会终止调度器并释放它所占用的资源,包括线程池等
调度器一旦被关闭,就不能再添加新的任务和触发器,需要重新创建新的调度器对象
在你的代码中,首先调用 scheduler.start() 启动调度器,使其开始执行任务;然后,通过 TimeUnit.MINUTES.sleep(1) 让程序休眠一分钟,等待任务执行;最后,调用 scheduler.shutdown() 来关闭调度器,停止任务的执行;这是一个典型的使用方式,可以控制调度器的生命周期

如果希望在稍后重新启动相同的调度器,需要创建一个新的调度器对象,并重新配置作业和触发器,然后再次调用 scheduler.start();注意,已经调用过 shutdown() 的调度器不能再次启动,需要创建一个新的调度器实例

这样的话就实现了一个简单的quartz动态定时任务了,更多详细的定时请看chatGPT 

实现一个简单的quartz系统  quartz实现动态任务管理系统

好的,以下是 SpringBoot 搭配 Quartz 实现动态定时任务的源码: 1. 首先,我们需要引入 QuartzSpringBoot 的依赖: ```xml <!-- Quartz相关依赖 --> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.2</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.3.2</version> </dependency> <!-- SpringBoot相关依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> ``` 2. 创建定时任务实体类,用于封装定时任务的信息,包括任务名称、任务组、任务类名、任务状态(是否启用)、任务表达式等: ```java @Entity @Table(name = "job_task") @Data public class JobTask implements Serializable { private static final long serialVersionUID = 1L; /** * ID */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; /** * 任务名称 */ @NotBlank(message = "任务名称不能为空") private String name; /** * 任务分组 */ @NotBlank(message = "任务分组不能为空") private String group; /** * 任务类名 */ @NotBlank(message = "任务类名不能为空") private String className; /** * 任务状态,0:禁用,1:启用 */ @NotNull(message = "任务状态不能为空") private Integer status; /** * 任务表达式 */ @NotBlank(message = "任务表达式不能为空") private String cronExpression; /** * 创建时间 */ private LocalDateTime createTime; /** * 最后一次修改时间 */ private LocalDateTime updateTime; } ``` 3. 创建定时任务的服务类,用于管理定时任务的增删改查等操作,同时也需要实现 `InitializingBean` 接口,在启动应用时加载已存在的定时任务: ```java @Service @AllArgsConstructor public class JobTaskService implements InitializingBean { private final Scheduler scheduler; private final JobTaskRepository jobTaskRepository; /** * 添加任务 * @param jobTask * @return * @throws Exception */ public boolean addJobTask(JobTask jobTask) throws Exception { if (jobTask == null || StringUtils.isBlank(jobTask.getCronExpression())) { return false; } if (StringUtils.isBlank(jobTask.getName()) || StringUtils.isBlank(jobTask.getClassName())) { throw new Exception("任务名称或任务类名不能为空"); } // 判断任务是否已存在 JobKey jobKey = JobKey.jobKey(jobTask.getName(), jobTask.getGroup()); if (scheduler.checkExists(jobKey)) { return false; } // 构建任务实例 JobDetail jobDetail = JobBuilder.newJob(getClass(jobTask.getClassName()).getClass()) .withIdentity(jobTask.getName(), jobTask.getGroup()) .build(); // 构建任务触发器 CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobTask.getCronExpression()); CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(jobTask.getName(), jobTask.getGroup()) .withSchedule(cronScheduleBuilder) .build(); // 注册任务和触发器 scheduler.scheduleJob(jobDetail, trigger); // 如果任务状态为启用,则立即启动任务 if (jobTask.getStatus() == 1) { scheduler.triggerJob(jobKey); } // 保存任务信息 jobTask.setCreateTime(LocalDateTime.now()); jobTask.setUpdateTime(LocalDateTime.now()); jobTaskRepository.save(jobTask); return true; } /** * 修改任务 * @param jobTask * @return * @throws Exception */ public boolean modifyJobTask(JobTask jobTask) throws Exception { if (jobTask == null || StringUtils.isBlank(jobTask.getCronExpression())) { return false; } if (StringUtils.isBlank(jobTask.getName()) || StringUtils.isBlank(jobTask.getClassName())) { throw new Exception("任务名称或任务类名不能为空"); } // 判断任务是否存在 JobKey jobKey = JobKey.jobKey(jobTask.getName(), jobTask.getGroup()); if (!scheduler.checkExists(jobKey)) { return false; } // 修改任务触发器 CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobTask.getCronExpression()); CronTrigger newTrigger = TriggerBuilder.newTrigger() .withIdentity(jobTask.getName(), jobTask.getGroup()) .withSchedule(cronScheduleBuilder) .build(); scheduler.rescheduleJob(TriggerKey.triggerKey(jobTask.getName(), jobTask.getGroup()), newTrigger); // 修改任务信息 JobTask oldJobTask = jobTaskRepository.findByNameAndGroup(jobTask.getName(), jobTask.getGroup()); oldJobTask.setClassName(jobTask.getClassName()); oldJobTask.setStatus(jobTask.getStatus()); oldJobTask.setCronExpression(jobTask.getCronExpression()); oldJobTask.setUpdateTime(LocalDateTime.now()); jobTaskRepository.save(oldJobTask); return true; } /** * 删除任务 * @param name * @param group * @return * @throws Exception */ public boolean deleteJobTask(String name, String group) throws Exception { JobKey jobKey = JobKey.jobKey(name, group); if (!scheduler.checkExists(jobKey)) { return false; } scheduler.deleteJob(jobKey); jobTaskRepository.deleteByNameAndGroup(name, group); return true; } /** * 获取所有任务 * @return */ public List<JobTask> getAllJobTask() { return jobTaskRepository.findAll(); } /** * 根据任务名称和分组获取任务信息 * @param name * @param group * @return */ public JobTask getJobTaskByNameAndGroup(String name, String group) { return jobTaskRepository.findByNameAndGroup(name, group); } /** * 获取任务类实例 * @param className * @return * @throws Exception */ private Object getClass(String className) throws Exception { Class<?> clazz = Class.forName(className); return clazz.newInstance(); } /** * 实现 InitializingBean 接口,在启动应用时加载已存在的定时任务 * @throws Exception */ @Override public void afterPropertiesSet() throws Exception { List<JobTask> jobTaskList = jobTaskRepository.findAll(); for (JobTask jobTask : jobTaskList) { if (jobTask.getStatus() == 1) { addJobTask(jobTask); } } } } ``` 4. 创建定时任务的控制器类,用于处理新增、修改、删除等请求: ```java @RestController @AllArgsConstructor @RequestMapping("/job") public class JobTaskController { private final JobTaskService jobTaskService; /** * 添加任务 * @param jobTask * @return * @throws Exception */ @PostMapping public ResponseEntity addJobTask(@RequestBody JobTask jobTask) throws Exception { boolean result = jobTaskService.addJobTask(jobTask); return result ? ResponseEntity.ok("任务添加成功") : ResponseEntity.badRequest().body("任务添加失败"); } /** * 修改任务 * @param jobTask * @return * @throws Exception */ @PutMapping public ResponseEntity modifyJobTask(@RequestBody JobTask jobTask) throws Exception { boolean result = jobTaskService.modifyJobTask(jobTask); return result ? ResponseEntity.ok("任务修改成功") : ResponseEntity.badRequest().body("任务修改失败"); } /** * 删除任务 * @param name * @param group * @return * @throws Exception */ @DeleteMapping("/{name}/{group}") public ResponseEntity deleteJobTask(@PathVariable String name, @PathVariable String group) throws Exception { boolean result = jobTaskService.deleteJobTask(name, group); return result ? ResponseEntity.ok("任务删除成功") : ResponseEntity.badRequest().body("任务删除失败"); } /** * 获取所有任务 * @return */ @GetMapping public ResponseEntity getAllJobTask() { List<JobTask> jobTaskList = jobTaskService.getAllJobTask(); return ResponseEntity.ok(jobTaskList); } /** * 根据任务名称和分组获取任务信息 * @param name * @param group * @return */ @GetMapping("/{name}/{group}") public ResponseEntity getJobTaskByNameAndGroup(@PathVariable String name, @PathVariable String group) { JobTask jobTask = jobTaskService.getJobTaskByNameAndGroup(name, group); return ResponseEntity.ok(jobTask); } } ``` 5. 创建定时任务的启动类,用于启动 SpringBoot 应用: ```java @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } /** * 注册定时任务调度器 * @return * @throws SchedulerException */ @Bean public SchedulerFactoryBean schedulerFactoryBean() throws SchedulerException { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); Properties properties = new Properties(); properties.put("org.quartz.scheduler.instanceName", "ChitGPTScheduler"); properties.put("org.quartz.threadPool.threadCount", "10"); schedulerFactoryBean.setQuartzProperties(properties); schedulerFactoryBean.setStartupDelay(5); return schedulerFactoryBean; } /** * 注册定时任务实例 * @return */ @Bean public Scheduler scheduler() { return schedulerFactoryBean().getScheduler(); } } ``` 以上就是 SpringBoot 搭配 Quartz 实现动态定时任务的源码,希望能对您有所帮助!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大白猫~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值