preface
- Traditional timers are hard coded. But sometimes business needs constant adjustment
Problem description
- We have developed a function of setting the alarm clock. This function must be developed by timer. But there is a problem. The timing is dynamic. So how do we achieve it? Please keep looking
brief introduction
- Timer is really a benefit in development. Through the timer, we saved a lot of manpower. We use timers to complete some tedious and regular things through code. In Java development, we can simply implement the timer function through the timer class. Since it's a spring boot course, today we'll take a look at the srpingboot integration timer
Traditional timer
- Here is the configuration of the previous course 1. springboot is intended to be a series of lectures. Therefore, the configuration is a link between the past and the future. I suggest you watch it in order.
@Component public class SimpleSchedule { @Autowired TestMapper testMapper; @Scheduled(cron = "*/6 * * * * ?") private void process() { List<Test> tests = testMapper.getTests(); System.out.println(tests); } }
- The writing of timer is also very simple. You only need to add @ Scheduled annotation on the class or method. Then configure the cron expression. Note here that the development timer annotation needs to be added to the spirngboot startup class.
@SpringBootApplication public class CrontabApplication { public static void main(String[] args) { SpringApplication.run(CrontabApplication.class, args); } }
- In the code, we use the simplest way.
- cron expression: Specifies that the task is executed at a specific time
- fixedDelay: indicates how long after the last task is executed. Parameter type: long, unit: ms
- fixedDelayString: the same as fixedDelay, except that the parameter type is String
- For example, the parameter "fix: fix" indicates that the task is executed every 5000 seconds, and "fix: fix" indicates that the task is executed every 5000 seconds
- fixedRateString: the same as fixedRate, except that the parameter type changes to String
- initialDelay: indicates how long the task will be delayed for the first time. The parameter type is long and the unit is ms
- initialDelayString: just like initialDelay, the parameter type is String
#Dynamic timer
- The above timer has been successfully configured. But now there is a demand that customers want to customize the frequency of timer execution through the page. The above code is written and executed once in 6S. If the customer wants to configure through visualization. After the configuration is completed, I can't rewrite the code manually. Then the dynamic timer is generated.
V1.0
- Since it is dynamic, we have to localize the data configured by customers. Of course, it is stored in the database.
- Correspondingly, we create a Mapper to query the scheduled task information. Because only expressions are configured here. The timer corresponding to the expression is not configured. Also for testing. The default expression here is one.
@Configuration public class ScheduleConfigV1 implements SchedulingConfigurer { @Autowired CronMapper cronMapper; @Autowired TestMapper testMapper; @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { scheduledTaskRegistrar.addTriggerTask(()-> { System.out.println("Execute timer task:" + LocalDateTime.now().toLocalTime()); List<Test> tests = testMapper.getTests(); System.out.println(tests); }, triggerContext -> { List<Cron> crons = cronMapper.getCron(); Cron cron = crons.get(0); return new CronTrigger(cron.getCron()).nextExecutionTime(triggerContext); }); } }
- To execute this code, we'd better turn off the previous static timer first. The effect is obvious. First, the database is configured to execute every 6 seconds. Then change the data to execute once every 2 seconds. See the effect.
-
We found that as long as the database information is modified. The frequency of scheduled tasks will be automatically modified. The most important thing is that we don't need to restart our code.
-
Although the above is dynamic configuration. But there is one drawback. It takes effect after modification and is effective after the next departure timer is executed. To put it bluntly, it is implemented once an hour at the beginning. During this period, the modification cannot take effect immediately. The configuration will not be refreshed until the next hour. The dynamics here can be understood as lazy dynamics.
V2.0
-
Although the above functions are dynamic. But for mass production, it must be unscientific. First of all, it is impossible to store only one piece of data in the database.
-
If multiple pieces of data are stored, how can multiple timing rules match with specific timers?
-
Since it is dynamic, how to control the switch of timer through database?
-
The scheduled task is actually started by the code scheduler schedule(task, new CronTrigger("*/2 * * * * ?")); Implemented. The object returned by this method is ScheduledFuture. Cancel the scheduled task through the canel method. Based on these two methods, let's improve our previous scheduled tasks.
Registar
- First, we provide a registrar whose function is to manage scheduled tasks. Provide the function of adding and deleting. On the node where the timer is added, we call scheduler schedule(task, new CronTrigger("*/2 * * * * ?")); To start a scheduled task. Call the previously obtained ScheduledFuture on the delete node to canel this scheduled task. The advantage of this is that we can control the switch of timed tasks at any time
public void addCronTask(Runnable task, String cron) { addCronTask(new CronTask(task,cron)); }
- The above addition requires a runnable and cron expression. A concurrent HashMap is used to manage the added runnable. Runnable is the key and ScheduledTask is the value.
public ScheduledTask scheduleCronTask(CronTask cronTask) { ScheduledTask scheduledTask; scheduledTask = new ScheduledTask(); scheduledTask.future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger()); return scheduledTask; }
- This builds a ScheduledTask object.
public final class ScheduledTask { public volatile ScheduledFuture<?> future; /** * Cancel scheduled task */ public void cancel() { ScheduledFuture<?> future = this.future; if (future != null) { future.cancel(true); } } }
- In this way, we can build a runnable thread and register the expression through the Registrar to start the thread to execute at a fixed frequency. Close the thread through remove.
SchedulingRunnable task = new SchedulingRunnable(TestMapper.class, "getTests", null); cronTaskRegistrar.addCronTask(task, "0/10 * * * * ?");
- The advantage of this is that we can update the scheduled task rules immediately when the table data is modified.
#Summary
-The above code has uploaded the value gitee
Click me to transmit
https://gitee.com/zxhTom/crontab.git
-
The following Java classes enable us to use the classes used this time. I want to know more about my private letter.
-
SchedulingConfigurer
-
DisposableBean
-
ConcurrentHashMap