Tarea de sincronización dinámica SpringBoot

Tarea de sincronización dinámica SpringBoot

Recientemente, me encontré con un escenario en el que springBoot ejecuta dinámicamente tareas de sincronización en mi trabajo. Especifico dinámicamente la frecuencia de ejecución de las tareas a través de la base de datos, deshabilito o inicio las tareas de sincronización, etc., al buscar información, resolví con éxito este escenario, vamos compartirlo juntos

1 Diseño de base de datos:

CREATE TABLE `spring_scheduled_cron` (
  `cron_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `cron_key` varchar(128) NOT NULL COMMENT '定时任务完整类名(该类必须继承 TimingTask类)',
  `cron_expression` varchar(20) NOT NULL COMMENT 'cron表达式',
  `task_explain` varchar(50) NOT NULL DEFAULT '' COMMENT '任务描述',
  `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态,1:正常;2:停用',
  PRIMARY KEY (`cron_id`),
  UNIQUE KEY `cron_key` (`cron_key`),
  UNIQUE KEY `cron_key_unique_idx` (`cron_key`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='定时任务表';

2 Escriba un asignador para consultar la base de datos

public interface ScheduleMapper {
    
    
    /**
     * 获取有效得定时任务
     * */
    @Select(" select cron_id,cron_key,cron_expression,task_explain,status 
              from spring_scheduled_cron ")
    public List<Schedule> getAll();
}

3 Clase de tarea personalizada

public abstract class TimingTask implements Runnable {
    
    
   private Schedule schedule;


    public Schedule getSchedule() {
    
    
        return schedule;
    }


    public void setSchedule(Schedule schedule) {
    
    
        this.schedule = schedule;
    }

    @Override
    public  void run() {
    
    
        this.task();
    }

    //执行的任务
    public abstract void  task();


    @Override
    public String toString() {
    
    
        return schedule.getCronId()+"   "+schedule.getCronKey();
    }

}

4 Escriba una clase de configuración de tarea dinámica

@Configuration
@EnableScheduling
public class DynamicTask implements SchedulingConfigurer {
    
    
    private static Logger LOGGER = LoggerFactory.getLogger(DynamicTask.class);

    //通过 registrar 可以注册 定时任务
    private volatile ScheduledTaskRegistrar registrar;


    //存放执行器
    private final ConcurrentHashMap<Integer, ScheduledFuture<?>> scheduledFutures = new ConcurrentHashMap<>();

    //存放当前执行的定时任务
    private final ConcurrentHashMap<Integer, CronTask> cronTasks = new ConcurrentHashMap<>();


    @Autowired
    private ScheduleMapper scheduleMapper;

    @Autowired
    private ApplicationContext applicationContext;



    @Override
    public void configureTasks(ScheduledTaskRegistrar registrar) {
    
    
        this.registrar = registrar;


        this.registrar.addTriggerTask(() -> {
    
    
            //查询定时任务
            List<Schedule> scheduleList = scheduleMapper.getAll();
            createTask(scheduleList);
        }
        , triggerContext -> new PeriodicTrigger(5L, TimeUnit.SECONDS).nextExecutionTime(triggerContext));

    }


    public void createTask(List<Schedule> scheduleList){
    
    

        if (!CollectionUtils.isEmpty(scheduleList)) {
    
    
            LOGGER.info("检测动态定时任务列表...");
            List<TimingTask> tts = new ArrayList<>();

            scheduleList .forEach(taskConstant -> {
    
    
                Object bean = null;
                try {
    
    
                    Class<?> taskClass = Class.forName(taskConstant.getCronKey());
                    //创建定时任务 去执行
                    bean = applicationContext.getBean(taskClass);
                } catch (ClassNotFoundException e) {
    
    
                    LOGGER.info("定时任务执行器{} 在Spring内找不到!",taskConstant.getCronKey());
                    return;
                }

                //获取bean后转换未 TimingTask 对象
                if(bean instanceof  TimingTask){
    
    
                    TimingTask timingTask =  (TimingTask)bean;
                   timingTask.setSchedule(taskConstant);
                    tts.add(timingTask);
                }
            });
            this.refreshTasks(tts.toArray(new TimingTask[tts.size()]));
        }
        LOGGER.info("定时任务加载完成!");

    }




    private void refreshTasks(TimingTask... tasks) {
    
    

        Set<Integer> taskIds = scheduledFutures.keySet();

        //查看任务是否已经存在,如果存在了就取消
        for (Integer taskId : taskIds) {
    
    
            if (!exists(taskId,tasks)) {
    
    
                scheduledFutures.get(taskId).cancel(false);
            }
        }

        for (TimingTask timingTask : tasks) {
    
    

            //校验 cron 表达式是否合法
            String expression = timingTask.getSchedule().getCronExpression();
            if (StringUtils.isBlank(expression) || !CronSequenceGenerator.isValidExpression(expression)) {
    
    
                LOGGER.error("定时任务"+timingTask.getSchedule().getCronKey()+" cron表达式不合法: " + expression);
                continue;
            }


            //如果配置一致,并且处于启用状态 则不需要重新创建定时任务
            if (scheduledFutures.containsKey(timingTask.getSchedule().getCronId())
                    && cronTasks.get(timingTask.getSchedule().getCronId()).getExpression().equals(expression) && timingTask.getSchedule().getStatus().equals("1")) {
    
    
                continue;
            }


            //如果策略执行时间发生了变化(如cron表达式修改,状态修改),则取消当前策略的任务,重新创建
            if (scheduledFutures.containsKey(timingTask.getSchedule().getCronId())) {
    
    
                scheduledFutures.remove(timingTask.getSchedule().getCronId()).cancel(false);
                cronTasks.remove(timingTask.getSchedule().getCronId());
            }

            //如果任务有效,才创建
           if(timingTask.getSchedule().getStatus().equals("1")){
    
    
               //创建定时任务执行
               CronTask task = new CronTask(timingTask, expression);
               ScheduledFuture<?> future = registrar.getScheduler().schedule(task.getRunnable(), task.getTrigger());
               cronTasks.put(timingTask.getSchedule().getCronId(), task);

               scheduledFutures.put(timingTask.getSchedule().getCronId(), future);
               LOGGER.info("添加定时任务===>{}   Cron表达式==>{}",timingTask.getSchedule().getCronKey(),timingTask.getSchedule().getCronExpression());
           }
        }
    }

    private boolean exists(Integer taskId,TimingTask... tasks) {
    
    
        for (TimingTask task : tasks) {
    
    
            if (task.getSchedule().getCronId().equals(taskId)) {
    
    
                return true;
            }
        }
        return false;
    }



    @PreDestroy
    public void destroy() {
    
    
        this.registrar.destroy();
    }
}

Terminaste, comienza la prueba:

Inserte datos en la base de datos, la tarea de cronometraje puede ejecutarse normalmente y el inicio y la detención de la tarea de cronometraje se pueden controlar cambiando la expresión cron o el estado de la base de datos sin reiniciar el servidor, y la frecuencia de ejecución de la tarea de cronometraje puede ser modificado.


GitHub 地址 :Spring-Boot-Schedule

Remitido a varios blogs de grandes personajes: espero que también te sea de utilidad:

Principio de la tarea de sincronización de Springboot y cómo crear tareas de sincronización de forma dinámica

Implementar dinámicamente la configuración de tareas de tiempo en Spring Boot

Supongo que te gusta

Origin blog.csdn.net/dndndnnffj/article/details/109674404
Recomendado
Clasificación