Solon

solon.scheduling.simple

v2.7.5 </> markdown
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon.scheduling.simple</artifactId>
</dependency>

1、描述

调度扩展插件。solon.scheduling 的简单实现。没有外部框架的依赖,且支持毫秒级的调度。(替代 solon.schedule;v1.11.4 后支持)

2、使用示例

启动类上,增加启用注解

// 启用 Scheduled 注解的任务
@EnableScheduling
public class JobApp {
    public static void main(String[] args) {
        Solon.start(JobApp.class, args);
    }
}

注解在类上

// 基于 Runnable 接口的模式
@Scheduled(fixedRate = 1000 * 3)
public class Job1 implements Runnable {
    @Override
    public void run() {
        System.out.println("我是 Job1 (3s)");
    }
}

注解在函数上(只对使用 @Component 注解的类有效)

// 基于 Method 的模式
@Component
public class JobBean {
    @Scheduled(fixedRate = 1000 * 3)
    public void job11(){
        System.out.println("我是 job11 (3s)");
    }

    @Scheduled(cron = "0/10 * * * * ? *")
    public void job12(){
        System.out.println("我是 job12 (0/10 * * * * ? *)");
    }

    //cron 表达式,支持时区的模式 
    @Scheduled(cron = "0/10 * * * * ? * +05")
    public void job13(){
        System.out.println("我是 job13 (0/10 * * * * ? *)");
    }

    //时区独立表示的模式
    @Scheduled(cron = "0/10 * * * * ? *", zone = "Asia/Shanghai")
    public void job14(){
        System.out.println("我是 job14 (0/10 * * * * ? *)");
    }
}

增加拦截处理(如果有需要?),v2.7.2 后支持:

@Slf4j
@Component
public class JobInterceptorImpl implements JobInterceptor {
    @Override
    public void doIntercept(Job job, JobHandler handler) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            handler.handle(job.getContext());
        } catch (Throwable e) {
            //记录日志
            TagsMDC.tag0("job");
            TagsMDC.tag1(job.getName());
            log.error("{}", e);

            throw e; //别吃掉
        } finally {
            //记录一个内部处理的花费时间
            long timespan = System.currentTimeMillis() - start;
            System.out.println("JobInterceptor: job=" + job.getName());
        }
    }
}

3、通过应用配置,可以控制有name的任务

# solon.scheduling.job.{job name} #要控制的job需要设置name属性
#
solon.scheduling.job.job1:
  cron: "* * * * * ?"  #重新定义调度表达式
  zone: "+08"
  fixedRate: 0
  fixedDelay: 0
  initialDelay: 0
  enable: true #用任务进行启停控制

4、@Scheduled 属性说明

属性说明备注
cron支持7位(秒,分,时,日期ofM,月,星期ofW,年)将并行执行
zone时区:+08 或 CET 或 Asia/Shanghai配合 cron 使用
fixedRate固定频率毫秒数(大于 0 时,cron 会失效)将并行执行
fixedDelay固定延时毫秒数(大于 0 时,cron 和 fixedRate 会失效)将串行执行
initialDelay初次执行延时毫秒数配合 fixedRate 或 fixedDelay 使用

提醒:只能选择 cron、fixedRate、fixedDelay 中的其中一个调度方式。

5、Cron 支持的表达式(与 quartz cron 兼容)

支持7位(秒,分,时,日期ofM,月,星期ofW,年)

  • 例:0 0/1 * * * ? *
  • 带时区,例:0 0/1 * * * ? * +050 0/1 * * * ? * -05
段位段名允许的值允许的特殊字符
1段0-59, - * /
2段0-59, - * /
3段小时0-23, - * /
4段1-31, - * ? / L W C
5段1-12 or JAN-DEC, - * /
6段周几1-7 or SUN-SAT (使用数字时,1代表周日), - * ? / L C #
7段年 (可选字段)empty, 1970-2099, - * /

6、支持对 @Scheduled 注解的函数进行拦截

如果需要别的什么处理?可以加个拦截器。比如,全局异常记录,或者改个线程名:

@EnableScheduling
public class JobApp {
    public static void main(String[] args) {
        Solon.start(JobApp.class, args, app->{
            //只对注解在函数上有效
            app.context().beanInterceptorAdd(Scheduled.class, inv->{
                Thread.currentThread().setName(inv.method().getMethod().getName());
                return inv.invoke();
            });
        });
    }
}

7、手动管理接口

详见:《Scheduled 调度 / 内部管理接口 IJobManager》

具体参考