Cronsmith - 终极 Cron 表达式生成器和解析器

使用devtools-cron4j进行Java任务调度
devtools-cron4j是一个轻量级的Java定时任务库,支持通过API定义cron表达式,内置多种调度器,并提供中断策略。文章展示了如何创建和解析cron表达式,进行任务测试及调度,还提供了丰富的示例代码供参考。

Cronsmith - 终极 Cron 表达式生成器和解析器

Cronsmith 是一个功能强大且多功能的 Java 工具库,旨在以直观、面向对象的方式处理 cron 表达式。它提供了一个高度灵活且用户友好的 API,轻松生成、解析和调度基于 cron 的任务。

Cronsmith 为无缝集成而构建,全面支持 Spring 和 Quartz 的 cron 表达式,确保与广泛使用的调度框架兼容。此外,它通过引入高级模式(例如与 ‘L’(最后一天)和 ‘W’(工作日)组合的多个数字)扩展了传统的 cron 语法,提供了更高的调度精度和灵活性。

功能特性

1. 面向对象的 CronExpression构建器

Cronsmith 允许开发者以直观、面向对象的方式构建复杂的 cron 表达式。这种方法便于自定义,避免了手动拼接字符串的麻烦。

Example:
 
@Test
public void test1() {
        CronExpression cronExpression = new CronBuilder()
            .everyMinute(5)
            .second(5)
            .andSecond(10)
            .toSecond(30);
        
        System.out.println(cronExpression.toString());
        assertEquals("5,10-30 */5 * * * ?", cronExpression.toString());
    }

@Test
public void test2() {
        CronExpression cronExpression = new CronBuilder()
            .everyMonth()
            .lastWeekday()
            .hour(10)
            .minute(1)
            .toMinute(15);
        
        System.out.println(cronExpression.toString());
        assertEquals("0 1-15 10 LW * ?", cronExpression.toString());
    }

@Test
public void test3() {
        CronExpression cronExpression = new CronBuilder()
            .year(2025)
            .toYear(2028)
            .everyMonth(2)
            .lastDay()
            .hour(12);
        
        System.out.println(cronExpression.toString());
        assertEquals("0 0 12 L */2 ? 2025-2028", cronExpression.toString());
}

@Test
public void test4() {
    CronExpression cronExpression = new CronBuilder()
        .everyYear(2026, 4)
        .everyMonth(5, 7, 1)
        .day(10).andDay(15).andDay(20).andLastDay(2)
        .everyHour(10, 15, 1)
        .at(10, 0)
        .andSecond(15).andSecond(30).andSecond(45);
    
    System.out.println(cronExpression.toString());
    assertEquals("0,15,30,45 10 10-15 10,15,20,L-2 MAY-JUL ? 2026/4",
            cronExpression.toString());
}

@Test
public void testK() {
        CronExpression cronExpression = new CronBuilder()
                .year(2025).toYear(2030).andYear(2035).toEnd(2)
                .everyMonth(2, 12, 2)
                .dayOfWeek(2, DayOfWeek.TUESDAY)
                .and(3, DayOfWeek.WEDNESDAY).andLastFri()
                .hour(2).andHour(3).andHour(4).toHour(17, 2)
                .minute(0).toMinute(12, 3).andMinute(15).toMinute(40, 2).andMinute(46)
                .andMinute(48).andMinute(50)
                .everySecond(5);
    
        System.out.println(cronExpression.toString());
        assertEquals("*/5 0-12/3,15-40/2,46,48,50 2,3,4-17/2 ? 2/2 TUE#2,WED#3,5L 2025-2030,2035/2",
                cronExpression.toString());
 }

2. Cron 表达式字符串解析与反向生成 CronExpression

Cronsmith 内置了一个强大的解析器,基于 ANTLR 构建,支持将已有的 cron 表达式字符串解析回结构化的 CronExpression 对象。

Example:
@Test
public void test1() {
        String cron = "0 15 10 ? * MON-FRI";
        CronExpression cronExpression = CRON.parse(cron);
        System.out.println(cronExpression);
        assertEquals(cron, cronExpression.toString());
}

@Test
public void test2() {
        String cron = "0 10,20,30 9-17 L * ?";
        CronExpression cronExpression = CRON.parse(cron);
        System.out.println(cronExpression);
        assertEquals(cron, cronExpression.toString());
}

@Test
public void test3() {
        String cron = "1,3,5,7,9 3-30/3 12-16 ? * TUE#1";
        CronExpression cronExpression = CRON.parse(cron);
        System.out.println(cronExpression);
        assertEquals(cron, cronExpression.toString());
}

@Test
public void test4() {
    String cron = "5-30/7 0-12/3,15-45/2 2,3,4-17/2 ? JAN-JUL MON-THU/2 2025-2033";
    CronExpression cronExpression = CRON.parse(cron);
    System.out.println(cronExpression);
    assertEquals(cron, cronExpression.toString());
}

Parse Tree:

cron
    second
        secondField
            rangeWithStep
                5
                -
                30
                /
                7
    <missing SPACE>
    minute
        minuteField
            rangeWithStep
                0
                -
                12
                /
                3
        ,
        minuteField
            rangeWithStep
                15
                -
                45
                /
                2
    <missing SPACE>
    hour
        hourField
            2
        ,
        hourField
            3
        ,
        hourField
            rangeWithStep
                4
                -
                17
                /
                2
    <missing SPACE>
    dayOfMonth
        dayOfMonthField
            ?
    <missing SPACE>
    month
        monthField
            monthRange
                monthName
                    JAN
                -
                monthName
                    JUL
    <missing SPACE>
    dayOfWeek
        dayOfWeekField
            weekdayRangeWithStep
                dayOfWeekName
                    MON
                -
                dayOfWeekName
                    THU
                /
                2
    year
        yearField
            yearRange
                2025
                -
                2030
    <EOF>

Retrieve next date and times from CronExpression

public static void main(String[] args) {
   String cron = "0 1,3,5-20 12-16 1,3,20,LW MAR-SEP ? 2026/1";
   CronExpression cronExpression = CRON.parse(cron);
   int N = 1000; // Retrieve 1000 items
   DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
   cronExpression.consume(ldt -> {
      System.out.println(ldt.format(dtf));
   }, N);
}

// Console:
// 2026-03-01 12:01:00
// 2026-03-01 12:03:00
// 2026-03-01 12:05:00
// 2026-03-01 12:06:00
// 2026-03-01 12:07:00
// 2026-03-01 12:08:00
// 2026-03-01 12:09:00
// 2026-03-01 12:10:00
// 2026-03-01 12:11:00
// 2026-03-01 12:12:00
// 2026-03-01 12:13:00
// 2026-03-01 12:14:00
// 2026-03-01 12:15:00
// 2026-03-01 12:16:00
// 2026-03-01 12:17:00
// 2026-03-01 12:18:00
// 2026-03-01 12:19:00
// 2026-03-01 12:20:00
// 2026-03-01 13:01:00
// 2026-03-01 13:03:00
// 2026-03-01 13:05:00
// ...

3. 内置调度器

Cronsmith 提供了内置调度器,支持基于 cron 表达式执行指定间隔的任务,轻松实现高效的重复任务调度。

Example: 每 5 秒调度一次任务
private ScheduledExecutorService scheduledExecutorService;

@Before
public void start() {
    scheduledExecutorService =
                Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors() * 2);
}

@Test
public void testSchedulerAndRunTenTimes() {
    int N = 10; // Run 10 times
    final CountDownLatch latch = new CountDownLatch(N);
    final AtomicInteger counter = new AtomicInteger();
    
    CronFuture future = new CronBuilder()
        .everySecond(5)
        .scheduler(scheduledExecutorService)
        .setDebuged(false)
        .runTask(() -> {
            System.out.println("Run task_" + counter.incrementAndGet());
            latch.countDown();
        }, N);
    
    try {
        latch.await();
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    
    future.cancel(true);
    assertTrue(future.isDone() && counter.get() == N);
}

@After
public void release() {
    scheduledExecutorService.shutdown();
}

4. 高级功能

支持指定年份的某一天

public static void main(String[] args) {
   int N = 1000;
   DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
   new CronBuilder().setZoneId(ZoneId.of("UTC")).year(2025).day(208).andDay(330).toLastDay()
                .at(12, 0).consume(ldt -> {
                    System.out.println(ldt.format(dtf));
                }, N);
}
// Console: 
// 2025-07-27 12:00:00
// 2025-11-26 12:00:00
// 2025-11-27 12:00:00
// 2025-11-28 12:00:00
// 2025-11-29 12:00:00
// 2025-11-30 12:00:00
// 2025-12-01 12:00:00
// 2025-12-02 12:00:00
// 2025-12-03 12:00:00
// 2025-12-04 12:00:00
// 2025-12-05 12:00:00
// 2025-12-06 12:00:00
// ...

支持指定年份的某周

public static void main(String[] args) {
    int N = 1000;
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    new CronBuilder().setZoneId(ZoneId.of("UTC")).everyYear().week(40).andWeek(45).Mon().toFri()
                .at(12, 0).consume(ldt -> {
                    System.out.println(ldt.format(dtf));
                }, N);
}
// Console: 
// 2025-09-29 12:00:00
// 2025-09-30 12:00:00
// 2025-10-01 12:00:00
// 2025-10-02 12:00:00
// 2025-10-03 12:00:00
// 2025-11-03 12:00:00
// 2025-11-04 12:00:00
// 2025-11-05 12:00:00
// 2025-11-06 12:00:00
// 2025-11-07 12:00:00
// 2026-09-28 12:00:00
// 2026-09-29 12:00:00
// 2026-09-30 12:00:00
// 2026-10-01 12:00:00
// 2026-10-02 12:00:00
// ...

安装

支持 Jdk1.8 或更高版本

在 Maven 项目中添加以下依赖:

<dependency>
    <groupId>com.github.paganini2008</groupId>
    <artifactId>cronsmith</artifactId>
    <version>1.0.0-beta</version>
</dependency>

Gradle 项目中添加:

dependencies {
    implementation 'com.github.paganini2008:cronsmith:1.0.0'
}

快速开始

  1. 在项目中添加 Cronsmith 依赖。
  2. 使用 CronBuilder 创建复杂的 cron 表达式。
  3. 通过 CRON.parse() 解析已有的 cron 表达式。
  4. 使用内置调度器调度任务。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值