任务调度

任务调度

任务调度技术

任务调度是特定业务场景下的定时任务处理,在分布式架构下,分布式调度框架的设计显得尤为重要。这里简要介绍了两种常用的分布式调度框架Quartz和xxl-job的特性、基本架构和参数配置,以加深了解。

Spring Schedule

spring自带一种基于注解的任务调度

在application中添加@EnableScheduling注解

```java
@SpringBootApplication
@EnableScheduling //开启定时任务功能
public class SpringbootTaskApplication {

public static void main(String[] args) {
    SpringApplication.run(SpringbootTaskApplication.class, args);
}

}

```

在定时任务类上添加规则和方法,使用cron表达式

```java
@Slf4j
@Component
public class MyJob {

//@Scheduled(cron = "0/${mytask.abc:15} * * * * ?") 在application.yml配置中添加参数可以通过配置方式指定规则 mytask.abc = 10 ;
@Scheduled(cron = "0,15,30,45 * * * * ?")
public void hello(){
    log.info("say hello");
}

}
```

Quartz

介绍

这是一个作业调度的开源项目,一般可用和spring结合使用,在实际开发中可用用 Quartz做一个定时任务,比如每小时执行一次,或每个月上午10点执行一次,每个月下午5点执行一次

安装

```xml

org.springframework.boot spring-boot-starter-quartz
```

使用

  • 编写任务信息
  • 编写任务处理规则
  • 配置调度中心(启动时开启任务调度)

首先,先编写job类

```java
public class Job1 implements Job {
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

private void before() {
    System.out.println("任务1:开始执行-" + dateFormat.format(new Date()));
}

@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
    before();
    System.out.println("任务1:业务逻辑。。。");
    after();
}

private void after() {
    System.out.println("任务1:执行结束");
    System.out.println();
}

```

再通过工具类配置规则

```java
@Component
public class QuartzSchedulerManager {
@Autowired
private Scheduler scheduler;

// 开始执行定时器
public void startJob() throws SchedulerException {
    startJob1(scheduler);
    startJob2(scheduler);
    scheduler.start();
}

// 获取Job信息
public String getJobInfo(String name, String group) throws SchedulerException {
    TriggerKey triggerKey = new TriggerKey(name, group);
    CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
    return String.format("time:%s,state:%s", cronTrigger.getCronExpression(),
            scheduler.getTriggerState(triggerKey).name());
}

// 修改某个任务的执行时间
public boolean modifyJob(String name, String group, String time) throws SchedulerException {
    Date date = null;
    TriggerKey triggerKey = new TriggerKey(name, group);
    CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
    String oldTime = cronTrigger.getCronExpression();
    if (!oldTime.equalsIgnoreCase(time)) {
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(time);
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group)
                .withSchedule(cronScheduleBuilder).build();
        date = scheduler.rescheduleJob(triggerKey, trigger);
    }
    return date != null;
}

// 暂停所有任务
public void pauseAllJob() throws SchedulerException {
    scheduler.pauseAll();
}

// 暂停某个任务
public void pauseJob(String name, String group) throws SchedulerException {
    JobKey jobKey = new JobKey(name, group);
    JobDetail jobDetail = scheduler.getJobDetail(jobKey);
    if (jobDetail == null)
        return;
    scheduler.pauseJob(jobKey);
}

// 恢复所有任务
public void resumeAllJob() throws SchedulerException {
    scheduler.resumeAll();
}

// 恢复某个任务
public void resumeJob(String name, String group) throws SchedulerException {
    JobKey jobKey = new JobKey(name, group);
    JobDetail jobDetail = scheduler.getJobDetail(jobKey);
    if (jobDetail == null)
        return;
    scheduler.resumeJob(jobKey);
}

// 删除某个任务
public void deleteJob(String name, String group) throws SchedulerException {
    JobKey jobKey = new JobKey(name, group);
    JobDetail jobDetail = scheduler.getJobDetail(jobKey);
    if (jobDetail == null)
        return;
    scheduler.deleteJob(jobKey);
}

// 启动任务1
private void startJob1(Scheduler scheduler) throws SchedulerException {
    // 通过JobBuilder构建JobDetail实例,JobDetail规定其job只能是实现Job接口的实例
    JobDetail jobDetail = JobBuilder.newJob(Job1.class).withIdentity("job1", "group1").build();
    // 基于表达式构建触发器
    CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
    // CronTrigger表达式触发器 继承于Trigger。TriggerBuilder 用于构建触发器实例
    CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("job1", "group1")
            .withSchedule(cronScheduleBuilder).build();
    scheduler.scheduleJob(jobDetail, cronTrigger);
}

// 启动任务2
private void startJob2(Scheduler scheduler) throws SchedulerException {
    // 通过JobBuilder构建JobDetail实例,JobDetail规定其job只能是实现Job接口的实例
    JobDetail jobDetail = JobBuilder.newJob(Job2.class).withIdentity("job2", "group2").build();
    // 基于表达式构建触发器
    CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
    // CronTrigger表达式触发器 继承于Trigger。TriggerBuilder 用于构建触发器实例
    CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("job2", "group2")
            .withSchedule(cronScheduleBuilder).build();
    scheduler.scheduleJob(jobDetail, cronTrigger);
}

}
```

若希望服务启动时运行,写以下配置类

```java
@Configuration
public class QuartzListener implements ApplicationListener {
@Autowired
private QuartzSchedulerManager quartzSchedulerManager;

// 初始启动quartz
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
    try {
        quartzSchedulerManager.startJob();
        System.out.println("任务已经启动...");
    } catch (SchedulerException e) {
        e.printStackTrace();
    }
}
// 初始注入scheduler
@Bean
public Scheduler scheduler() throws SchedulerException{
    SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory();
    return schedulerFactoryBean.getScheduler(); 
}

}
```

若希望通过api启动任务类,在controler里执行以下api

```java
@RestController
@RequestMapping("")
public class QuartzController {
@Autowired
private QuartzSchedulerManager quartzSchedulerManager;

// @Description: 获取定时器信息
@GetMapping("/info")
public String getQuartzJob(String name, String group) {
    String info = null;
    try {
        info = quartzSchedulerManager.getJobInfo(name, group);
    } catch (SchedulerException e) {
        e.printStackTrace();
    }
    return info;
}

// @Description: 修改定时器的 执行时间
@PostMapping("/modify")
public boolean modifyQuartzJob(String name, String group, String time) {
    boolean flag = true;

    if (!CronExpression.isValidExpression(time)) {
        throw new RuntimeException("非法的cron表达式");
    }

    try {
        flag = quartzSchedulerManager.modifyJob(name, group, time);
    } catch (SchedulerException e) {
        e.printStackTrace();
    }
    return flag;
}

// @Description: 启动所有定时器
@PostMapping("/start")
public void startQuartzJob() {
    try {
        quartzSchedulerManager.startJob();
    } catch (SchedulerException e) {
        e.printStackTrace();
    }
}

// @Description: 暂停指定 定时器
@PostMapping(value = "/pause")
public void pauseQuartzJob(String name, String group) {
    try {
        quartzSchedulerManager.pauseJob(name, group);
    } catch (SchedulerException e) {
        e.printStackTrace();
    }
}

// 暂停所有定时器
@PostMapping(value = "/pauseAll")
public void pauseAllQuartzJob() {
    try {
        quartzSchedulerManager.pauseAllJob();
    } catch (SchedulerException e) {
        e.printStackTrace();
    }
}

// 删除指定定时器
@PostMapping(value = "/delete")
public void deleteJob(String name, String group) {
    try {
        quartzSchedulerManager.deleteJob(name, group);
    } catch (SchedulerException e) {
        e.printStackTrace();
    }
}

}
```

XXL-JOB

介绍

xxl-job是基于分布式集群的任务调度模块
单机情况下,一个任务调度中心可以发起一种任务调度
但在集群情况下,多个任务调度中心就会重复发一种任务调度
如我们希望在每个月1号清空积分,但用了集群分布式,有了多个调度中心,那么每个调度中心都会清空积分,这样任务就重复了,我们希望只有一个任务中心发起任务调度即可,而xxl-job就是专门解决分布式集群任务调度的开源框架

  • 执行服务:编写任务信息
  • 调度服务:编写任务规则
  • 执行服务:配置调度中心(启动时开启任务调度)

cron表达式

对于cron表达式,如果自己写的话会比较麻烦,可以使用网络上的cron表达式在线 生成工具https://cron.qqe2.com/

CC BY-NC-SA 4.0 Deed | 署名-非商业性使用-相同方式共享
最后更新时间:2025-07-19 05:39:17