前言:

项目需要执行定时任务,该类定时任务只需要实现类似Spring原生的@Scheudle注解的定时方法即可,无需考虑分片、刷新及重启,且因项目是多实例,所以需要考虑实现分布式,考察了目前开源的几款分布式定时任务产品

xxl-job 需要部署server端,考虑项目不需要依赖这么重的第三方的server,所以被pass

elastic-job-lite 这个需要的zk版本要3.6以上 公司已有的zk环境是3.4.5 所以不想再单独部署zk,所以也被pass

quartz 分布式定时任务是依靠数据库悲观锁的机制实现的,只需要依赖数据库,项目本身是有数据库存储依赖的,对项目的侵入性较小

以下为改造过程

  1. 引入maven依赖

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
    <version>2.3.2.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.25</version>
    </dependency>
  2. 增加配置application.properties

    # 定时任务配置
    spring.quartz.job-store-type=jdbc
    spring.quartz.wait-for-jobs-to-complete-on-shutdown=true
    spring.quartz.overwrite-existing-jobs=true
    spring.quartz.startup-delay=10S
    spring.quartz.properties.org.quartz.scheduler.instanceName=exampleInstanceName
    spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO
    spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
    spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_
    spring.quartz.properties.org.quartz.jobStore.useProperties=false
    spring.quartz.properties.org.quartz.jobStore.isClustered=true
    spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=5000
    spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
    spring.quartz.properties.org.quartz.threadPool.threadCount=10
    spring.quartz.properties.org.quartz.threadPool.threadPriority=5
    spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
  3. 执行sql

    项目中存在数据库的连接配置,存在spring-boot-starter-jdbc依赖

    #
    # In your Quartz properties file, you'll need to set
    # org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    #
    #
    # By: Ron Cordell - roncordell
    # I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM. DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
    DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
    DROP TABLE IF EXISTS QRTZ_LOCKS;
    DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
    DROP TABLE IF EXISTS QRTZ_CALENDARS; CREATE TABLE QRTZ_JOB_DETAILS(
    SCHED_NAME VARCHAR(120) NOT NULL,
    JOB_NAME VARCHAR(190) NOT NULL,
    JOB_GROUP VARCHAR(190) NOT NULL,
    DESCRIPTION VARCHAR(250) NULL,
    JOB_CLASS_NAME VARCHAR(250) NOT NULL,
    IS_DURABLE VARCHAR(1) NOT NULL,
    IS_NONCONCURRENT VARCHAR(1) NOT NULL,
    IS_UPDATE_DATA VARCHAR(1) NOT NULL,
    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
    ENGINE=InnoDB; CREATE TABLE QRTZ_TRIGGERS (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(190) NOT NULL,
    TRIGGER_GROUP VARCHAR(190) NOT NULL,
    JOB_NAME VARCHAR(190) NOT NULL,
    JOB_GROUP VARCHAR(190) NOT NULL,
    DESCRIPTION VARCHAR(250) NULL,
    NEXT_FIRE_TIME BIGINT(13) NULL,
    PREV_FIRE_TIME BIGINT(13) NULL,
    PRIORITY INTEGER NULL,
    TRIGGER_STATE VARCHAR(16) NOT NULL,
    TRIGGER_TYPE VARCHAR(8) NOT NULL,
    START_TIME BIGINT(13) NOT NULL,
    END_TIME BIGINT(13) NULL,
    CALENDAR_NAME VARCHAR(190) NULL,
    MISFIRE_INSTR SMALLINT(2) NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
    REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
    ENGINE=InnoDB; CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(190) NOT NULL,
    TRIGGER_GROUP VARCHAR(190) NOT NULL,
    REPEAT_COUNT BIGINT(7) NOT NULL,
    REPEAT_INTERVAL BIGINT(12) NOT NULL,
    TIMES_TRIGGERED BIGINT(10) NOT NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
    ENGINE=InnoDB; CREATE TABLE QRTZ_CRON_TRIGGERS (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(190) NOT NULL,
    TRIGGER_GROUP VARCHAR(190) NOT NULL,
    CRON_EXPRESSION VARCHAR(120) NOT NULL,
    TIME_ZONE_ID VARCHAR(80),
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
    ENGINE=InnoDB; CREATE TABLE QRTZ_SIMPROP_TRIGGERS
    (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(190) NOT NULL,
    TRIGGER_GROUP VARCHAR(190) NOT NULL,
    STR_PROP_1 VARCHAR(512) NULL,
    STR_PROP_2 VARCHAR(512) NULL,
    STR_PROP_3 VARCHAR(512) NULL,
    INT_PROP_1 INT NULL,
    INT_PROP_2 INT NULL,
    LONG_PROP_1 BIGINT NULL,
    LONG_PROP_2 BIGINT NULL,
    DEC_PROP_1 NUMERIC(13,4) NULL,
    DEC_PROP_2 NUMERIC(13,4) NULL,
    BOOL_PROP_1 VARCHAR(1) NULL,
    BOOL_PROP_2 VARCHAR(1) NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
    ENGINE=InnoDB; CREATE TABLE QRTZ_BLOB_TRIGGERS (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(190) NOT NULL,
    TRIGGER_GROUP VARCHAR(190) NOT NULL,
    BLOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
    ENGINE=InnoDB; CREATE TABLE QRTZ_CALENDARS (
    SCHED_NAME VARCHAR(120) NOT NULL,
    CALENDAR_NAME VARCHAR(190) NOT NULL,
    CALENDAR BLOB NOT NULL,
    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
    ENGINE=InnoDB; CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_GROUP VARCHAR(190) NOT NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
    ENGINE=InnoDB; CREATE TABLE QRTZ_FIRED_TRIGGERS (
    SCHED_NAME VARCHAR(120) NOT NULL,
    ENTRY_ID VARCHAR(95) NOT NULL,
    TRIGGER_NAME VARCHAR(190) NOT NULL,
    TRIGGER_GROUP VARCHAR(190) NOT NULL,
    INSTANCE_NAME VARCHAR(190) NOT NULL,
    FIRED_TIME BIGINT(13) NOT NULL,
    SCHED_TIME BIGINT(13) NOT NULL,
    PRIORITY INTEGER NOT NULL,
    STATE VARCHAR(16) NOT NULL,
    JOB_NAME VARCHAR(190) NULL,
    JOB_GROUP VARCHAR(190) NULL,
    IS_NONCONCURRENT VARCHAR(1) NULL,
    REQUESTS_RECOVERY VARCHAR(1) NULL,
    PRIMARY KEY (SCHED_NAME,ENTRY_ID))
    ENGINE=InnoDB; CREATE TABLE QRTZ_SCHEDULER_STATE (
    SCHED_NAME VARCHAR(120) NOT NULL,
    INSTANCE_NAME VARCHAR(190) NOT NULL,
    LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
    CHECKIN_INTERVAL BIGINT(13) NOT NULL,
    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
    ENGINE=InnoDB; CREATE TABLE QRTZ_LOCKS (
    SCHED_NAME VARCHAR(120) NOT NULL,
    LOCK_NAME VARCHAR(40) NOT NULL,
    PRIMARY KEY (SCHED_NAME,LOCK_NAME))
    ENGINE=InnoDB; CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
    CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP); CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
    CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
    CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
    CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
    CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
    CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
    CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
    CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
    CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
    CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
    CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
    CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE); CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
    CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
    CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
    CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
    CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
    CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP); commit;
  4. 以下是代码列表清单

实现逻辑:

1> ScheduleJobInit 初始化时加载所有AbstractJob 的子类

2> 获取子类的 beanName ,及ScheduleTag注解注解的方法名称methodName,及注解的cron()方法

3> 根据beanName+methodName 生产jobId

4> 如果外部有 beanName+methodName+cron 配置取外部配置,没值取注解的cron()值

5> 具体需要定时执行的类和方法 需满足 在spring容器里、实现AbstractJob 接口、方法上加上ScheduleTag(cron="") 注解信息即可

  • ScheduleJobEntity job信息类


    @Data
    public class ScheduleJobEntity { public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";
    private String jobId;
    private String beanName;
    private String methodName;
    private String params;
    private String cronExpression; public String getJobId() {
    return StrUtil.join("_", beanName, methodName);
    }
    }
  • ScheduleUtils schedule工具类


    /**
    * 定时任务工具类
    */
    public class ScheduleUtils {
    private final static String JOB_NAME = "job_";
    private final static String JOB_PARAMS_NAME = "params";
    private final static String JOB_CRON_NAME = "cron"; /**
    * 获取触发器key
    */
    public static TriggerKey getTriggerKey(String jobId) {
    return TriggerKey.triggerKey(JOB_NAME + jobId);
    } /**
    * 获取jobKey
    */
    public static JobKey getJobKey(String jobId) {
    return JobKey.jobKey(JOB_NAME + jobId);
    } public static void initJob(Scheduler scheduler, Class jobClass, Map<String, String> properties) {
    ScheduleJobEntity scheduleJob = new ScheduleJobEntity();
    scheduleJob.setBeanName(StringUtils.uncapitalize(jobClass.getSimpleName()));
    Method[] methods = MethodUtils.getMethodsWithAnnotation(jobClass, ScheduleTag.class);
    for (Method method : methods) {
    ScheduleTag scheduleTag = method.getAnnotation(ScheduleTag.class);
    String params = "";
    String cron = "";
    if (scheduleTag != null) {
    params = scheduleTag.params();
    cron = scheduleTag.corn();
    }
    if (CollectionUtil.isNotEmpty(properties)) {
    String paramsDynamic = properties.get(joinKey(scheduleJob.getBeanName(), method.getName(), JOB_PARAMS_NAME));
    String cronDynamic = properties.get(joinKey(scheduleJob.getBeanName(), method.getName(), JOB_CRON_NAME));
    if (StringUtils.isNotEmpty(paramsDynamic)) {
    params = paramsDynamic;
    }
    if (StringUtils.isNotEmpty(cronDynamic)) {
    cron = cronDynamic;
    }
    }
    scheduleJob.setMethodName(method.getName());
    scheduleJob.setParams(params);
    scheduleJob.setCronExpression(cron);
    CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, scheduleJob.getJobId());
    if (cronTrigger == null) {
    createScheduleJob(scheduler, scheduleJob);
    } else {
    updateScheduleJob(scheduler, scheduleJob);
    }
    }
    } private static String joinKey(String beanName, String methodName, String key) {
    return StrUtil.join("_", beanName, methodName, key);
    } /**
    * 获取表达式触发器
    */
    public static CronTrigger getCronTrigger(Scheduler scheduler, String jobId) {
    try {
    return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
    } catch (SchedulerException e) {
    throw new QeteshException(e, "获取定时任务CronTrigger出现异常");
    }
    } /**
    * 创建定时任务
    */
    public static void createScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) {
    try {
    // 构建job信息
    JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(scheduleJob.getJobId())).build(); // 表达式调度构建器
    CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
    .withMisfireHandlingInstructionDoNothing(); // 按新的cronExpression表达式构建一个新的trigger
    CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduleJob.getJobId())).withSchedule(scheduleBuilder).build(); // 放入参数,运行时的方法可以获取
    jobDetail.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, JSONUtil.toJsonStr(scheduleJob)); scheduler.scheduleJob(jobDetail, trigger); } catch (SchedulerException e) {
    throw new QeteshException(e, "创建定时任务失败");
    }
    } /**
    * 更新定时任务
    */
    public static void updateScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) {
    try {
    TriggerKey triggerKey = getTriggerKey(scheduleJob.getJobId()); // 表达式调度构建器
    CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
    .withMisfireHandlingInstructionDoNothing(); CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getJobId()); // 按新的cronExpression表达式重新构建trigger
    trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); // 参数
    trigger.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, JSONUtil.toJsonStr(scheduleJob)); scheduler.rescheduleJob(triggerKey, trigger); } catch (SchedulerException e) {
    throw new QeteshException(e, "更新定时任务失败");
    }
    }
    }
  • ScheduleRunnable 具体任务执行反射线程类


    /**
    * 执行定时任务
    */
    public class ScheduleRunnable implements Runnable {
    private final Object target;
    private final Method method;
    private final String params; public ScheduleRunnable(String beanName, String methodName, String params) throws NoSuchMethodException, SecurityException {
    this.target = SpringContextHolder.getBean(beanName);
    this.params = params;
    if (StringUtils.isNotBlank(params)) {
    this.method = target.getClass().getDeclaredMethod(methodName, String.class);
    } else {
    this.method = target.getClass().getDeclaredMethod(methodName);
    }
    } @Override
    public void run() {
    try {
    ReflectionUtils.makeAccessible(method);
    if (StringUtils.isNotBlank(params)) {
    method.invoke(target, params);
    } else {
    method.invoke(target);
    }
    } catch (Exception e) {
    throw new QeteshException(e, "执行定时任务失败");
    }
    }
    }
  • ScheduleJob job类


    /**
    * 定时任务
    */
    @Slf4j
    public class ScheduleJob extends QuartzJobBean { private static final ExecutorService service = Executors.newSingleThreadExecutor(); @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
    String jsonJob = context.getMergedJobDataMap().getString(ScheduleJobEntity.JOB_PARAM_KEY);
    ScheduleJobEntity scheduleJob = JSONUtil.toBean(jsonJob, ScheduleJobEntity.class);
    // 任务开始时间
    long startTime = System.currentTimeMillis();
    try {
    // 执行任务
    log.info("任务准备执行,任务ID:" + scheduleJob.getJobId());
    ScheduleRunnable task = new ScheduleRunnable(scheduleJob.getBeanName(),
    scheduleJob.getMethodName(), scheduleJob.getParams());
    Future<?> future = service.submit(task);
    future.get();
    // 任务执行总时长
    long times = System.currentTimeMillis() - startTime;
    log.info("任务执行完毕,任务ID:" + scheduleJob.getJobId() + " 总共耗时:" + times + "毫秒");
    } catch (Exception e) {
    log.error("任务执行失败,任务ID:" + scheduleJob.getJobId(), e);
    // 任务执行总时长
    long times = System.currentTimeMillis() - startTime;
    log.info("任务执行完毕,任务ID:" + scheduleJob.getJobId() + " 总共耗时:" + times + "毫秒");
    } }
    }
  • ScheduleTag 注解类

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Documented
    @Inherited
    public @interface ScheduleTag { String corn() default "";
    String params() default "";
    }
  • AbstractJob job接口类,如果需要定时执行的方法需要继承该接口

    public interface AbstractJob {
    
    }
  • ScheduleJobInit 初始化器

    @Component
    @RequiredArgsConstructor(onConstructor = @__(@Autowired))
    public class ScheduleJobInit implements ApplicationContextAware, InitializingBean { private final Scheduler scheduler;
    private final JobConfig jobConfig;
    private ApplicationContext applicationContext; @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;
    } @Override
    public void afterPropertiesSet() throws Exception {
    Collection<AbstractJob> jobList = applicationContext.getBeansOfType(AbstractJob.class).values();
    if (CollectionUtil.isNotEmpty(jobList)) {
    jobList.forEach(job -> ScheduleUtils.initJob(scheduler, job.getClass(), jobConfig.getProperties()));
    } }
    }
  • SimpleJob 简单示例job ,必须在spring容器内

    @Slf4j
    @Component
    @RequiredArgsConstructor(onConstructor = @__(@Autowired))
    public class SimpleJob implements AbstractJob { // 每5秒执行一次
    @ScheduleTag(corn = "*/5 * * * * ?")
    public void test() {
    log.info("test start...");
    }
    }

这里如果需要在配置文件里配置cron,需要增加如下配置

properties aicc.job.properties.simpleJob_test_cron=0 0/1 * * * ?

规则如下:

aicc.job.properties.beanName(类名首字母小写).methodName(方法名).cron

Quartz分布式定时任务的更多相关文章

  1. Spring整合Quartz分布式定时任务

    概述虽然单个Quartz实例能给予你很好的Job调度能力,但它不能满足典型的企业需求,如可伸缩性.高可靠性满足.假如你需要故障转移的能力并能运行日益增多的 Job,Quartz集群势必成为你应用的一部 ...

  2. 基于spring+quartz的分布式定时任务框架

    问题背景 我公司是一个快速发展的创业公司,目前有200人,主要业务是旅游和酒店相关的,应用迭代更新周期比较快,因此,开发人员花费了更多的时间去更=跟上迭代的步伐,而缺乏了对整个系统的把控 没有集群之前 ...

  3. 3分钟掌握Quartz.net分布式定时任务的姿势

    引言 长话短说,今天聊一聊分布式定时任务,我的流水账笔记: ASP.NET Core+Quartz.Net实现web定时任务 AspNetCore结合Redis实践消息队列 细心朋友稍一分析,就知道还 ...

  4. spring quartz分布式任务计划

    spring quartz分布式任务计划 环境: 通过maven管理的spring mvc工程,且已经成功连接数据库. 数据库表结构 /*Table structure for table `qrtz ...

  5. Elastic-Job - 分布式定时任务框架

    Elastic-Job - 分布式定时任务框架 摘要 Elastic-Job是ddframe中dd-job的作业模块中分离出来的分布式弹性作业框架.去掉了和dd-job中的监控和ddframe接入规范 ...

  6. Spring整合Quartz分布式调度

    前言 为了保证应用的高可用和高并发性,一般都会部署多个节点:对于定时任务,如果每个节点都执行自己的定时任务,一方面耗费了系统资源,另一方面有些任务多次执行,可能引发应用逻辑问题,所以需要一个分布式的调 ...

  7. Spring整合Quartz分布式调度(山东数漫江湖)

    前言 为了保证应用的高可用和高并发性,一般都会部署多个节点:对于定时任务,如果每个节点都执行自己的定时任务,一方面耗费了系统资源,另一方面有些任务多次执行,可能引发应用逻辑问题,所以需要一个分布式的调 ...

  8. Spring Boot Quartz 分布式集群任务调度实现

    Spring Boot Quartz 主要内容 Spring Scheduler 框架 Quartz 框架,功能强大,配置灵活 Quartz 集群 mysql 持久化定时任务脚本(tables_mys ...

  9. Java分布式定时任务

    分布式定时任务 elastic-job 可以实现任务分片 quartz 可以把任务存入数据库,实时生成任务(添加数据库添加定时任务) 文档 中文翻译 翻译2

  10. springboot整合xxl-job分布式定时任务【图文完整版】

    一.前言 定时任务有很多种,有一些大的框架也有一些简单的实现. 比如常见的: JDK的Timer和TimerTask Quartz异步任务调度框架 分布式定时任务XXL-JOB Spring Task ...

随机推荐

  1. NLog 在NetCore中实现多实例注入DI, 实现多租户模式

    通常, 我们在使用了 Microsoft.Extensions.DependencyInjection DI框架的情况下, 我们一般通过 .ConfigureLogging((HostBuilderC ...

  2. appium-解决uiautomatorviewer不能定位android7以上版本元素的方法

    上图是android10模拟器,发现我们是无法连接模拟器识别的 解决方法: 在模拟器内打开指定页面然后截图,最后保存为uix文件,然后用adb拉到本地,一共四个命令,可以保存为.bat文件快捷执行(这 ...

  3. direasch目录扫描

    direasch目录扫描工具 安装: 1.github源码下载解压 使用 git 安装:(推荐git clone https://github.com/maurosoria/dirsearch.git ...

  4. [rCore学习笔记 030] 虚拟地址与地址空间

    时隔很久,终于忙里偷闲可以搞一搞rCore,上帝啊,保佑我日更吧,我真的很想学会. 导读部分 首先还是要看官方文档. 我决定看一遍然后自己表述一遍(智将). 这里反复提到MMU,就是因为之前学MCU的 ...

  5. img标签src引用网络图片,响应403的解决方法

    在html页面加入<meta name="referrer" content="no-referrer">标签,就可以解决页面加载网络图片的问题, ...

  6. 解密prompt系列42. LLM通往动态复杂思维链之路

    最近大家都在探讨和尝试复现OpenAI O1的思考效果,解码出的关键技术方向,包括之前已经探讨过的Inference Time Scaling在推理过程中进行路径决策和选择.但想要更优的Inferen ...

  7. 使用原生Web开发技术为在线客服系统提供网页版配置工具

    升讯威在线客服与营销系统是基于 .net core / WPF 开发的一款在线客服软件,宗旨是: 开放.开源.共享.努力打造 .net 社区的一款优秀开源产品. 背景 随着下载私有化部署的用户越来越多 ...

  8. Vulhub Apache Httpd漏洞复现

    目录 前言 多后缀解析漏洞 换行解析漏洞(CVE-2017-15715) 2.4.49 路径穿越漏洞(CVE-2021-41773) 2.4.50 路径穿越漏洞(CVE-2021-42013) SSR ...

  9. dotnet学习笔记-专题03-RabbitMQ-01

    专题03--RabbitMQ 1. RabbitMQ安装 服务端 使用如下sh脚本安装: #!/bin/sh sudo apt-get install curl gnupg apt-transport ...

  10. Java单例对象同步问题探讨

    在本文中,作者向大家讲述了Single Call 模式的原理,同时也介绍了Single Call 模式的实现问题.  评论: 邓明 (dengming@cn.ibm.com), 高级信息系统工程师, ...