Cron表达式详细讲解,平常看一看就记住了

7,200 阅读9分钟

CRON表达式是一个用于设置计划任务的字符串,其由几个字段组成,每个字段代表任务在相应时间、日期或时间间隔执行的规则。CRON表达式最初是在类Unix操作系统中使用的,而现在它已经被广泛地应用于各种操作系统和编程语言中。

一个标准的CRON表达式由五个至六个部分组成,分别为:秒(second)、分钟(minute)、小时(hour)、日(day-of-month)、月(month)和年(year)。其中,年并不是必需的部分,只有在需要特定年份的任务时才使用。

1、Cron表达式的结构

CRON表达式基本格式为:* * * * *,每个星号代表一个字段的取值范围。CRON表达式中的每个字段都可以使用以下符号和数字设置特定的任务执行时间:

  • 数字:表示对应的时间点值(如1表示1点)
  • 星号(*):表示该字段的所有可能值,如分钟字段中的星号表示每分钟的任何时间点
  • 逗号(,):用于分割字段中的多个取值,如“2,5,10”表示取值为2、5、10的时间点
  • 连接符(-):用于指定时间段,如“1-5”表示取值范围为1到5的所有时间点
  • 斜杠(/):用于指定时间步长,如“*/10”表示每隔10个时间点执行一次任务
特殊字符含义
*所有可能值
/步长
,列举多个值,表示具体时间点
-表示范围,如1-5表示取值范围为1到5的所有时间点
?日和星期任选其一
Llast,表示某个月最后一天或某个星期的最后一天
W工作日(周一至周五)
#表示某个月的第几个星期几,如4#2表示某月的第二个星期四

下面是CRON表达式中每个字段的取值范围和示例:

  • 秒(second):0~59
  • 分钟(minute):0~59
  • 小时(hour):0~23
  • 日(day):1~31
  • 月(month):1~12或JAN-DEC
  • 年(year):可选,1970~2099或者空

举个例子,一个CRON表达式为 0 0/5 * * * ? 表示每隔5分钟执行一次任务。这个表达式可以被解读为“在每小时的0分0秒开始,每隔5分钟运行一次”。另一个示例是 0 0 0 ? * MON-FRI,它表示每个工作日的午夜零点执行任务。

除了上述基本的取值设置方式外,还有一些常用的高级特性,如:

  • @yearly:等同于0 0 0 1 1 *,表示每年的1月1日零点执行任务。
  • @monthly:等同于0 0 0 1 * *,表示每月的1日零点执行任务。
  • @weekly:等同于0 0 0 * * 0,表示每周日午夜执行任务。
  • @daily:等同于0 0 0 * * *,表示每天午夜执行任务。
  • @hourly:等同于0 0 * * * *,表示每小时的0分0秒执行任务。

CRON表达式广泛应用于各种计划任务场景,如定时备份、自动化测试、定时数据清理、定时发送邮件等。在使用CRON表达式时,需要注意一些问题:

  • CRON表达式中的时间是基于服务器所在时区而非本地时区进行计算的。
  • CRON表达式并不支持秒级别的时间设置,最小单位为分钟。
  • 在设置CRON表达式时,需要考虑任务运行时间的长短以及系统资源的可用性,以免造成系统瓶颈或任务重叠等问题。

2、使用示例

下面是CRON表达式的结构和一些示例:

  1. 秒(Second):0~59
  2. 分钟(Minute):0~59
  3. 小时(Hour):0~23
  4. 日(Day):1~31
  5. 月(Month):1~12或JAN-DEC
  6. 星期(Weekday):0~6或SUN-SAT(0代表星期天)

每个字段可以使用以下符号和数字来设置,以下是一些示例:

  • 0 0 * * * :每天凌晨零点执行任务
  • 0 12 * * ? :每天中午12点执行任务
  • 30 8 * * 1-5 :周一至周五早上8:30执行任务
  • 0 23 ? * FRI :每周五晚上11点执行任务
  • 0/5 * * * * ? :每5秒执行任务
  • 0 0 1 * * :每个月的第一天凌晨执行任务
  • 0 0 8 1,15 * :每月1日和15日早上8点执行任务
  • 0 0 2 1 * ? * 表示在每月的1日的凌晨2点调整任务
  • 0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业
  • 0 15 10 ? 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午10:15执行作
  • 0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
  • 0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
  • 0 0 12 ? * WED 表示每个星期三中午12点
  • 0 0 12 * * ? 每天中午12点触发
  • 0 15 10 ? * * 每天上午10:15触发
  • 0 15 10 * * ? 每天上午10:15触发
  • 0 15 10 * * ? * 每天上午10:15触发
  • 0 15 10 * * ? 2005 2005年的每天上午10:15触发
  • 0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发
  • 0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
  • 0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
  • 0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发
  • 0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发
  • 0 15 10 ? * MON-FRI 周一至周五的上午10:15触发
  • 0 15 10 15 * ? 每月15日上午10:15触发
  • 0 15 10 L * ? 每月最后一日的上午10:15触发
  • 0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发
  • 0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发
  • 0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发

希望这些示例能够帮助您更好地了解CRON表达式的使用方法。

3、使用场景

常见的使用场景包括:

  • 定时任务:如定时发送邮件、备份数据、执行清理操作等;
  • 批处理任务:如处理大量数据、生成报表、更新缓存等;
  • 自动化测试:如定时运行测试用例、检查程序错误等。

以下是几个常见的在Java中使用CRON表达式的框架和工具以及示例:

  1. Quartz Scheduler

Quartz Scheduler是一个功能强大的开源任务调度框架,在Java中应用非常广泛。下面是一个使用Quartz Scheduler实现定时任务的示例:

// 定义一个Job类,实现Job接口
public class HelloJob implements Job {
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("Hello Quartz!");
    }
}

// 创建JobDetail对象,用于指定要执行的Job类
JobDetail job = JobBuilder.newJob(HelloJob.class).build();

// 创建Trigger对象,用于定义任务执行的规则
Trigger trigger = TriggerBuilder.newTrigger()
    .withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?"))
    .build();

// 将Job和Trigger绑定在一起进行调度
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);

上述代码定义了一个HelloJob类,该类实现了Job接口,并重写了execute方法,该方法会输出"Hello Quartz!"。接着,我们创建了一个JobDetail对象,指定了要执行的HelloJob类;然后,通过TriggerBuilder创建了一个Trigger对象,并使用CronScheduleBuilder设置了任务执行的CRON表达式(每隔5分钟执行一次)。

  1. Spring Framework

Spring Framework是一个流行的开源框架,提供了丰富的功能和扩展性,其中也包含了对任务调度的支持。下面是一个使用Spring Framework实现定时任务的示例:

// 定义一个Task类,实现Runnable接口
public class HelloTask implements Runnable {
    public void run() {
        System.out.println("Hello Spring!");
    }
}

// 配置TaskScheduler对象,用于执行定时任务
@Configuration
@EnableScheduling
public class AppConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
        taskRegistrar.addTriggerTask(new HelloTask(), new CronTrigger("0 0/10 * * * ?"));
    }

    @Bean(destroyMethod = "shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(10);
    }
}

上述代码定义了一个HelloTask类,该类实现了Runnable接口,并重写了run方法,该方法会输出"Hello Spring!"。接着,我们在AppConfig类中通过@EnableScheduling注解启用了任务调度功能,实现了SchedulingConfigurer接口,并重写了configureTasks方法,该方法使用CronTrigger设置了任务执行的CRON表达式(每隔10分钟执行一次)。

  1. Spring Batch

Spring Batch是一个用于处理大规模批量数据的开源框架,其中也包含了对任务调度的支持。下面是一个使用Spring Batch实现批处理任务的示例:

// 定义一个Job类
@Configuration
public class BatchConfig {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public Step step() {
        return stepBuilderFactory.get("step")
            .tasklet(new Tasklet() {
                public RepeatStatus execute(StepContribution contribution, ChunkContext context) {
                    System.out.println("Hello Spring Batch!");
                    return RepeatStatus.FINISHED;
                }
            })
            .build();
    }

    @Bean
    public Job job() {
        return jobBuilderFactory.get("job")
            .incrementer(new RunIdIncrementer())
            .start(step())
            .build();
    }
}

// 配置BatchConfigurer对象,用于执行批处理任务
@Configuration
@EnableBatchProcessing
public class AppConfig extends DefaultBatchConfigurer {
    @Override
    protected JobRepository createJobRepository() throws Exception {
        MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean();
        factory.afterPropertiesSet();
        return factory.getObject();
    }

    @Override
    protected JobLauncher createJobLauncher() throws Exception {
        SimpleJobLauncher launcher = new SimpleJobLauncher();
        launcher.setTaskExecutor(new SimpleAsyncTaskExecutor());
        launcher.setJobRepository(createJobRepository());
        launcher.afterPropertiesSet();
        return launcher;
    }

    @Bean
    public JobLauncherCommandLineRunner runner(JobExplorer explorer, JobRepository repo,
                                               JobLauncher launcher) {
        return new JobLauncherCommandLineRunner(explorer, launcher, repo);
    }
}

上述代码定义了一个BatchConfig类,该类中通过@EnableBatchProcessing注解启用了批处理任务调度功能,并实现了两个@Bean方法,分别用于定义批处理任务的StepJob。对于Step,我们使用Tasklet实现了一个简单的任务,该任务会输出"Hello Spring Batch!"。对于Job,使用了RunIdIncrementer生成每次执行任务的唯一标识符。

然后,我们在AppConfig类中继承了DefaultBatchConfigurer类,并重写了createJobRepositorycreateJobLauncher方法,用于创建一个MapJobRepository对象作为任务存储,并设置一个SimpleJobLauncher对象作为任务启动器。最后,使用@Bean注解定义了一个JobLauncherCommandLineRunner对象,用于启动任务。

4、生成工具

推荐几个线上小工具,便于使用:

image.png

看到这里你以了解到:CRON表达式是一个十分强大和灵活的工具,它能够帮助我们轻松地完成计划任务,提高系统的稳定性和效率。在使用CRON表达式时,需要仔细思考任务的执行规则,并根据实际情况进行合理设置和调整。