Spring Timing Task Details of spring schedule and spring-quartz

Keywords: Programming Spring xml Java encoding

There are currently three main types of java timer tasks categorized technically by implementation:

(1) Java's native java.util.Timer class, which allows you to schedule a java.util.TimerTask task.This allows your program to execute at a certain frequency, but not at a specified time; and job classes need to integrate java.util.TimerTask, which is typically less used.
(2) Quartz, a more powerful dispatcher, allows your program to execute at a specified time or at a certain frequency; it needs to inherit org.springframework.scheduling.quartz.QuartzJobBean, which is a bit complex to configure, so it is generally used to integrate quartz with spring, which will be described in more detail later;
(3) The task that comes with Spring 3.0, spring schedule, can be considered a lightweight Quartz and is much simpler to use than Quartz.
To summarize, there are two ways to use timed tasks in spring: spring schedule and spring-quartz, which we will focus on next.Spring packages need to be introduced before use.

<!-- spring -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${org.springframework.version}</version>
    <type>jar</type>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>${org.springframework.version}</version>
    <type>jar</type>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${org.springframework.version}</version>
    <type>jar</type>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>${org.springframework.version}</version>
</dependency>


spring schedule
1. How xml is configured:

1)application.xml:

Start by introducing the task namespace in application.xml and defining tasks through the task tag.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                           http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd">
 
    <task:scheduler id="myScheduler"/>
    <task:scheduled-tasks scheduler="myScheduler">
        <task:scheduled ref="doSomethingTask" method="doSomething" cron="0 * * * * *"/>
    </task:scheduled-tasks>
</beans>


2) Task class:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class DoSomethingTask {
 
    public void doSomething() {
        System.out.println("do something");
    }
}


2,@schedule Notes:

1)application.xml

Also introduce task's namespace in application.xml and enable annotation-driven timed tasks.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                           http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd">
 
    <task:annotation-driven/> 
</beans>


2) Task class:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
@Component
public class DoSomethingTask {
    @Scheduled(cron="0 * * * * *")
    public void doSomething() {
        System.out.println("do something");
    }
}


3. Cron expression:

It consists of 6-7 items separated by spaces.From left to right are seconds, minutes, hours, days, months, weeks, years (omitted).Values can be numbers or the following symbols:
*: All values match
?: It doesn't matter, it doesn't care, it's usually in the day of the week
,: or
/: Incremental value
-: Interval

For example:

0 * * * * *: every minute (when the second is 0)
0 * * * *: Hours (when seconds and minutes are 0)
*/10 * * * * *: Every 10 seconds
0 5/15 * * *: 5, 20, 35, 50 points per hour
0 0 9,13 * *: 9 and 13 o'clock per day


4. @Scheduled annotation has two other properties: fixedRate and fixedDelay

1) Fixed Delay sets how long to execute the next task after the last one ends;

2) Fixed Rate sets the interval between the start of the previous task and the start of the next task;

Note: It is recommended to use fixedRate and fixedDelay for timed tasks that emphasize task intervals, and cron expression for timed tasks that emphasize task execution at a certain time and moment.

5. Concurrent execution

1) spring schedule's timed tasks default to single-threaded

The way to do this is to wait for the last task to finish before proceeding to the next one.(Both cron and fixedDelay and fixedRate follow this principle).Here are some examples:

Example 1: Execute through cron timer: Task runs 6s, once every 5s

//Create timed tasks using annotations
<task:annotation-driven/>
 
@Component
public class testTask {
    private Logger logger = LoggerFactory.getLogger(testTask.class);
    @Scheduled(cron = "0/5 * * * * ?")
    public void doTask() {
        logger.info(Thread.currentThread().getName()+"===task run");
        Thread.sleep(6*1_000);
        logger.info(Thread.currentThread().getName()+"===task end");
    }
}
 
//The logs are as follows
2018-06-11 16:03:00.006 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:03:06.013 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 16:03:10.115 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:03:17.267 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 16:03:20.055 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:03:26.164 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end


As you can see from the log, spring schedule handles single threaded by default, and the next task will wait until the previous one is finished.

Example 2: Replace with fixedDelay

@Scheduled(fixedDelay = 5*1_000)
public void doTask() throws InterruptedException {
    logger.info(Thread.currentThread().getName()+"===task run");
    Thread.sleep(6*1_000);
    logger.info(Thread.currentThread().getName()+"===task end");
}
//The logs are as follows:
2018-06-11 16:31:08.122 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:31:14.139 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 16:31:19.149 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:31:25.261 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 16:31:30.269 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:31:36.385 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end


From the log, you can see that the end time of the task starts running again after 5 seconds.

Example 3: fixedRate

@Scheduled(fixedRate = 5*1_000)
public void doTask() throws InterruptedException {
        logger.info(Thread.currentThread().getName()+"===task run");
        Thread.sleep(6*1_000);
        logger.info(Thread.currentThread().getName()+"===task end");
}
//Journal
2018-06-11 16:54:36.118 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:54:42.580 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 16:54:42.607 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:54:48.632 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 16:54:48.639 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:54:55.188 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end


From the log, you can see that when the previous task is finished, the next one starts immediately because fixedRate sets the interval between the start time of the previous task and the start time of the next task.

Example 4: fixedRate

In the example above, the run time is changed from 6s to 2s, and the logs are as follows:

2018-06-11 17:08:43.086 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 17:08:45.093 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 17:08:48.025 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 17:08:50.083 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 17:08:53.239 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 17:08:55.245 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end


The result is consistent with what we inferred, and the start time interval between the two tasks is 5s.

2) Configure parallel processing

The example above is the same task, which won't trigger if the previous one hasn't finished running yet. That's not a big problem.However, it is not reasonable to assume that there are multiple tasks in the system and that the default spring schedule is single-threaded, resulting in different tasks not running at the same time.Solution:

Method 1: Configure multiple threads, but this can cause problems that are triggered after the same task has not finished running.

<task:scheduler id="scheduler" pool-size="2" />


Method 2: Let the tasks run in different scheduler s

<task:scheduler id="myScheduler1"/>
<task:scheduler id="myScheduler2"/>
<task:scheduled-tasks scheduler="myScheduler1">
    <task:scheduled ref="doSomethingTask" method="doSomething" cron="${0 * * * * *}"/>
</task:scheduled-tasks>
<task:scheduled-tasks scheduler="myScheduler2">
    <task:scheduled ref="doOtherThingTask" method="doOtherThing" cron="${0 * * * * *}"/>
</task:scheduled-tasks>

 

spring-quartz
There are quartz.jar, spring-context-support.jar that need to be introduced in maven.

Example:

1) Define a task class: (Quatz for spring integration does not require any classes to be integrated)

@Service
public class QuartzTest {
 
    public void test(){
        System.out.println("It's time to run :" + new Date().toString());
        //TODO Execute Task Logic
        //........
    }
}


2) spring-quartz.xml configuration:

a)SimpleTrigger method:

<bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref local="quartzTestTrigger" />
        </list>
    </property>
</bean>
<bean id="quartzTestTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
    <property name="jobDetail" ref="quartzTestJob"/>
    <!-- 20 Run in seconds -->
    <property name="startDelay" value="20000" />
    <!-- Repeat every thirty seconds -->
    <property name="repeatInterval" value="30000" />
</bean>
 
<bean id="quartzTestJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject" ref="quartzTest"></property>
    <property name="targetMethod" value="autoRun"></property>
    <property name="concurrent" value="false"></property><!--Run without concurrency-->
</bean>


b)CronTrigger method:

<bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref local="quartzTestTrigger" />
        </list>
    </property>
    <property name="startupDelay" value="500"/>
</bean>
<bean id="quartzTestTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail" ref="quartzTestJob"/>
    <property name="cronExpression">
        <value>0 */1 * * * ?</value>
    </property>
</bean>
 
<bean id="quartzTestJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject" ref="quartzTest"></property>
    <property name="targetMethod" value="autoRun"></property>
    <property name="concurrent" value="false"></property><!--Run without concurrency-->
</bean>


Finally, include the application-quartz.xml above in the spring main configuration file application.xml.

Posted by blacksnday on Fri, 10 Apr 2020 21:09:05 -0700