Talking about the way of using timed tasks in springboot

  • 2021-10-13 07:47:30
  • OfStack

springboot Timing Task

There are many methods in springboot environment, and two of them have been used here. 1. Use annotations. 2. By implementing interfaces.

Although it is relatively simple to use annotations, it is difficult to use annotations only if the project requires users to modify the timing cycle. So you can use the way to implement the interface. Through the implementation of the interface, you can modify the task execution cycle according to the needs when the project is running, just close the original task and then start a new task.

1. Use annotation

First, you need to add the @ EnableScheduling annotation under the startup class (@ EnableAsync is the annotation to turn on asynchronism)


package com.fongtech.cli;
 
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
 
@SpringBootApplication
@MapperScan("com.fongtech.cli.mbg.*.**")
@EnableAsync
@EnableScheduling 
public class SpringbootAdminApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(SpringbootAdminApplication.class, args);
    }
 
}

Next add @ Component and @ Scheduled (cron = "00/1***? ") annotation, where 'cron' in @ Scheduled () has a fixed format. (@ Async annotation means asynchronous is turned on)


@Slf4j
@Component
public class AsyncTaskConfiguration {
 
    /**
     *  Check the task list every minute, judge the task type and execute the corresponding task 
     *  According to the actual task implementation, limit the number of tasks to be performed 
     */
    @Scheduled(cron = "0 0/1 * * * ? ")
    @Async
    public void startCommonTask() throws Exception {
        log.info("startCommonTask  start........." + Thread.currentThread().getName());
        commonTaskService.startCommonTask();
        log.info("startCommonTask  end........." + Thread.currentThread().getName());
 
    }}

2. Use the way to implement the interface

By implementing SchedulingConfigurer interface, timing tasks can be operated. The way to implement interfaces is more flexible than using annotations, but it needs to write code and is relatively cumbersome.

The implementation tool classes are as follows:


package com.fongtech.cli.admin.tasktime;
 
import com.fongtech.cli.common.util.BeanUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.SchedulingException;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.config.TriggerTask;
import org.springframework.scheduling.support.CronTrigger;
 
import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
 
/**
 * @author linb
 * @date 2020/6/15 11:16
 */
@Configuration
//@EnableScheduling
public class DefaultSchedulingConfigurer implements SchedulingConfigurer {
    private ScheduledTaskRegistrar taskRegistrar;
    private Set<ScheduledFuture<?>> scheduledFutures = null;
    private Map<String, ScheduledFuture<?>> taskFutures = new ConcurrentHashMap<>();
 
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        this.taskRegistrar = taskRegistrar;
    }
 
    @SuppressWarnings("unchecked")
    private Set<ScheduledFuture<?>> getScheduledFutures() {
        if (scheduledFutures == null) {
            try {
                // spring Choose different fields for different versions scheduledFutures
                scheduledFutures = (Set<ScheduledFuture<?>>) BeanUtils.getProperty(taskRegistrar, "scheduledTasks");
            } catch (NoSuchFieldException e) {
                throw new SchedulingException("not found scheduledFutures field.");
            }
        }
        return scheduledFutures;
    }
 
    /**
     *  Add Task 
     */
    public void addTriggerTask(String taskId, TriggerTask triggerTask) {
        if (taskFutures.containsKey(taskId)) {
            throw new SchedulingException("the taskId[" + taskId + "] was added.");
        }
        TaskScheduler scheduler = taskRegistrar.getScheduler();
        ScheduledFuture<?> future = scheduler.schedule(triggerTask.getRunnable(), triggerTask.getTrigger());
        getScheduledFutures().add(future);
        taskFutures.put(taskId, future);
    }
 
    /**
     *  Cancel a task 
     */
    public void cancelTriggerTask(String taskId) {
        ScheduledFuture<?> future = taskFutures.get(taskId);
        if (future != null) {
            future.cancel(true);
        }
        taskFutures.remove(taskId);
        getScheduledFutures().remove(future);
    }
 
    /**
     *  Reset task 
     */
    public void resetTriggerTask(String taskId, TriggerTask triggerTask) {
        cancelTriggerTask(taskId);
        addTriggerTask(taskId, triggerTask);
    }
 
    /**
     *  Task number 
     */
    public Set<String> taskIds() {
        return taskFutures.keySet();
    }
 
    /**
     *  Is there a task 
     */
    public boolean hasTask(String taskId) {
        return this.taskFutures.containsKey(taskId);
    }
 
    /**
     *  Has the task scheduling been initialized and completed 
     */
    public boolean inited() {
        return this.taskRegistrar != null && this.taskRegistrar.getScheduler() != null;
    }
}

The operation classes that automatically start tasks after the project starts are as follows:


package com.fongtech.cli.admin.tasktime;
 
import com.fongtech.cli.admin.service.IAuthLoginService;
import com.fongtech.cli.admin.service.IBackupsService;
import com.fongtech.cli.admin.service.IDictionnaryEntryService;
import com.fongtech.cli.mbg.model.entity.AuthLogin;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.config.TriggerTask;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
 
/**
 *  Execute after the project starts, 
 */
@Slf4j
@Component
@Order(value = 1)
public class CmdRunner implements CommandLineRunner {
 
    @Autowired
    private DefaultSchedulingConfigurer defaultSchedulingConfigurer;
    @Autowired
    private IDictionnaryEntryService dictionnaryEntryService;
    @Autowired
    private IBackupsService backupsService;
    @Autowired
    private IAuthLoginService authLoginService;
 
    @Override
    public void run(String... args) throws Exception {
        log.info("------ Start the database backup timing task according to the preset backup cycle ");
        while (!defaultSchedulingConfigurer.inited())
        {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
 
            }
        }
        String cron = dictionnaryEntryService.getEntryValueByName("CRON_VALUE");
        // Backup tasks are performed according to administrator user rights by default 
        AuthLogin authLogin = authLoginService.query().eq(AuthLogin::getLogin_user, "admin").getOne();
        // Start the thread and execute the backup task according to the time in the original table 
        defaultSchedulingConfigurer.addTriggerTask("task",
                new TriggerTask(
                        () -> System.out.println("=====---------- Start a timed task =-----------");,
                        new CronTrigger(cron)));
    }
}

Pause timed tasks:


defaultSchedulingConfigurer.cancelTriggerTask("task");

Related articles: