项目中偶尔会用到定时任务的执行,比如定时发短信,定时发送对账文件等等,今天,我们就一起学习下,在Spring中如何实现定时器!
1 老生常谈说Timer
1.1 介绍
废话不多说,我们来了解下它的身份:
- 所在包:java.util
- 作者:Josh Bloch
- 出生日期:JDK1.3
- 直系亲属:Object
- 个人简历:一堆English
别怕,下面是英语学习时间:
A facility for threads to schedule tasks for future execution in a background thread. Tasks may be scheduled for one-time execution, or for repeated execution at regular intervals.
线程用于计划任务以在后台线程中将来执行的工具。可以安排任务一次执行或定期执行重复任务。
Corresponding to each Timer object is a single background thread that is used to execute all of the timer’s tasks, sequentially. Timer tasks should complete quickly. If a timer task takes excessive time to complete, it “hogs” the timer’s task execution thread. This can, in turn, delay the execution of subsequent tasks, which may “bunch up” and execute in rapid succession when (and if) the offending task finally completes.
与每个Timer对象相对应的是一个后台线程,该线程用于依次执行所有Timer的任务。计时器任务应快速完成。如果计时器任务花费过多时间来完成,它将“占用”计时器的任务执行线程。反过来,这可能会延迟后续任务的执行,这可能会“累加”并在有问题的任务最终完成时(以及是否)迅速连续执行。
After the last live reference to a Timer object goes away and all outstanding tasks have completed execution, the timer’s task execution thread terminates gracefully (and becomes subject to garbage collection). However, this can take arbitrarily long to occur. By default, the task execution thread does not run as a daemon thread, so it is capable of keeping an application from terminating. If a caller wants to terminate a timer’s task execution thread rapidly, the caller should invoke the timer’s cancel method.
在最后一个对Timer对象的实时引用消失并且所有未完成的任务均已完成执行之后,计时器的任务执行线程会正常终止(并接受垃圾回收)。但是,这可能要花很长时间。默认情况下,任务执行线程不会作为守护程序线程运行,因此它能够防止应用程序终止。如果调用方想快速终止计时器的任务执行线程,则调用方应调用计时器的cancel方法。
If the timer’s task execution thread terminates unexpectedly, for example, because its stop method is invoked, any further attempt to schedule a task on the timer will result in an IllegalStateException, as if the timer’s cancel method had been invoked.
如果计时器的任务执行线程意外终止,例如,由于调用了它的stop方法,则在计时器上计划任务的任何进一步尝试都将导致IllegalStateException,就好像计时器的cancel方法已被调用一样。
This class is thread-safe: multiple threads can share a single Timer object without the need for external synchronization.
此类是线程安全的:多个线程可以共享一个Timer对象,而无需外部同步。
This class does not offer real-time guarantees: it schedules tasks using the Object.wait(long) method.
此类不提供实时保证:它使用Object.wait(long)方法调度任务。
Java 5.0 introduced the java.util.concurrent package and one of the concurrency utilities therein is the ScheduledThreadPoolExecutor which is a thread pool for repeatedly executing tasks at a given rate or delay. It is effectively a more versatile replacement for the Timer/TimerTask combination, as it allows multiple service threads, accepts various time units, and doesn’t require subclassing TimerTask (just implement Runnable). Configuring ScheduledThreadPoolExecutor with one thread makes it equivalent to Timer.
Java 5.0引入了java.util.concurrent包,其中的并发实用程序之一是ScheduledThreadPoolExecutor,它是一个线程池,用于以给定的速率或延迟重复执行任务。实际上,它是Timer / TimerTask组合的更通用的替代品,因为它允许多个服务线程,接受各种时间单位,并且不需要子类化TimerTask(只需实现Runnable)。使用一个线程配置ScheduledThreadPoolExecutor使其等效于Timer。
Implementation note: This class scales to large numbers of concurrently scheduled tasks (thousands should present no problem). Internally, it uses a binary heap to represent its task queue, so the cost to schedule a task is O(log n), where n is the number of concurrently scheduled tasks.
实现说明:此类可扩展为同时执行的大量计划任务(成千上万个也不会出现问题)。在内部,它使用二进制堆表示其任务队列,因此调度任务的成本为O(log n),其中n是同时调度的任务数。
Implementation note: All constructors start a timer thread.
实现说明:所有构造函数都启动一个计时器线程。
1.2 入门实例
我们直接在main方法中实例化一个Timer:
Timer timer = new Timer();
当我想调用timer的方法时:
见名知意,大家可以每个都试一下看,这里我们用scheduleAtFixedRate举例:
这个方法有三个参数,依次是TimerTask的实例,延迟执行时间,持续时间,也就是说,上述代码的意思是:
启动后延迟2秒开始执行run方法中的内容,每隔3秒执行一次
运行main方法,结果如下:
原谅我的Gif中的鼠标乱入~囧
至此,Timer的介绍到此暂时告一段落。
2. ScheduledExecutorService->Timer的升级版
细心的同学可能会注意到,你的1.2中的timer明明报错了嘛?
其实不是的,那只是IDE给我的一个比较友好的提示,内容是:
ScheduledExecutorService,它来了!老规矩,还是先了解下它的身份信息:
- 所在包:java.util.concurrent
- 作者:Doug Lea
- 出生日期:JDK1.5
- 性别:interface
- 上层亲属:
我们打开文档,进一步了解下它 看文档,我只用Dash
没错,英语学习时间又到了!
An ExecutorService that can schedule commands to run after a given delay, or to execute periodically.
ExecutorService可以安排命令在给定的延迟后运行或定期执行。
The schedule methods create tasks with various delays and return a task object that can be used to cancel or check execution. The scheduleAtFixedRate and scheduleWithFixedDelay methods create and execute tasks that run periodically until cancelled.
schedule方法创建具有各种延迟的任务,并返回可用于取消或检查执行的任务对象。 scheduleAtFixedRate和scheduleWithFixedDelay方法创建并执行定期运行的任务,直到被取消为止。
Commands submitted using the Executor.execute(Runnable) and ExecutorService submit methods are scheduled with a requested delay of zero. Zero and negative delays (but not periods) are also allowed in schedule methods, and are treated as requests for immediate execution.
使用Executor.execute(Runnable)和ExecutorService submit 方法提交的命令的计划延迟为零。 schedule方法中还允许零延迟和负延迟(但在周期调用中不可以),并将其视为立即执行的请求。
All schedule methods accept relative delays and periods as arguments, not absolute times or dates. It is a simple matter to transform an absolute time represented as a Date to the required form. For example, to schedule at a certain future date, you can use: schedule(task, date.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS). Beware however that expiration of a relative delay need not coincide with the current Date at which the task is enabled due to network time synchronization protocols, clock drift, or other factors.
所有schedule方法都接受相对延迟和周期作为参数,而不是绝对时间或日期作为参数。将代表日期的绝对时间转换为所需的形式很简单。例如,要在某个将来的日期进行调度,可以使用:schedule(task,date.getTime()-System.currentTimeMillis(),TimeUnit.MILLISECONDS)。但是请注意,由于网络时间同步协议,时钟漂移或其他因素,相对延迟的到期时间不必与启用任务的当前日期一致。
The Executors class provides convenient factory methods for the ScheduledExecutorService implementations provided in this package.
Executors类为此程序包中提供的ScheduledExecutorService实现提供了方便的工厂方法。
我们再来看下ScheduledExecutorService下的所有方法:
既然只有四个方法,我们就逐个写个小例子,试验一下:
其实不止newScheduledThreadPool这一种线程池,其他的会在后续其他文章中介绍,本文只介绍定时相关的newScheduledThreadPool。
schedule(Runnable command, long delay, TimeUnit unit)
/**
* 测试ScheduledExecutorService中的schedule[Runnable]
*/
public static void testScheduledExecutorService1(){
ScheduledExecutorService scheduledExecutorService =
Executors.newScheduledThreadPool(1);
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
System.out.println(" 使用ScheduledExecutorService延迟执行任务" + new Date());
}
}, 2, TimeUnit.SECONDS);
scheduledExecutorService.shutdown();
}
我们设置其中的run方法在延迟2秒后执行,在main方法中调用该方法,得到:
该方法为一次性方法,即非周期性的,只执行一次
schedule(Callable callable, long delay, TimeUnit unit)
这个也是个一次性的方法,和schedule(Runnable command, long delay, TimeUnit unit)的区别是,它有返回值:
/**
* 测试ScheduledExecutorService中的schedule[Callable]
*/
public static void testScheduledExecutorService2() throws ExecutionException, InterruptedException {
ScheduledExecutorService scheduledExecutorService =
Executors.newScheduledThreadPool(1);
ScheduledFuture<String> s = scheduledExecutorService.schedule(new Callable<String>() {
@Override
public String call() throws Exception {
return "hello Aran!";
}
}, 2, TimeUnit.SECONDS);
String theValue = s.get();
System.out.println("得到的返回值是:" + theValue);
scheduledExecutorService.shutdown();
}
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
private final AtomicInteger count = new AtomicInteger(0);
/**
* 测试ScheduledExecutorService中的scheduleAtFixedRate
*/
public void testScheduledExecutorService3() {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
ScheduledExecutorService scheduledExecutorService =
Executors.newScheduledThreadPool(1);
Runnable beep = new Runnable(){
int i = 0;
@Override
public void run() {
count.getAndIncrement();
System.out.println("输出时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
if(count.get() == 5){
System.out.println("条件达标,结束定时任务!");
scheduledExecutorService.shutdown();
}
}
};
scheduledExecutorService.scheduleAtFixedRate(beep,3, 4, TimeUnit.SECONDS);
}
其中,我们用count的值对是否结束定时任务进行判断,AtomicInteger是一种原子操作,我们后续会单独介绍。
运行代码,结果如下:
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
/**
* 测试ScheduledExecutorService中的scheduleWithFixedDelay
*/
public void testScheduledExecutorService4() {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
ScheduledExecutorService scheduledExecutorService =
Executors.newScheduledThreadPool(1);
Runnable beep = new Runnable(){
int i = 0;
@Override
public void run() {
count.getAndIncrement();
System.out.println("输出时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
if(count.get() == 5){
System.out.println("条件达标,结束定时任务!");
scheduledExecutorService.shutdown();
}
}
};
scheduledExecutorService.scheduleWithFixedDelay(beep,3, 4, TimeUnit.SECONDS);
}
运行上面的代码,结果如下:
铺垫了这么多,主角也该出现了!
3. Spring中的定时任务
3.1 大名鼎鼎的Quartz
相信大家对Quartz还是比较熟悉的,它涉及到的东西稍多,我们打开源码目录:
本篇文章我们暂时只介绍比较常用的,上图中选中的两个!
3.1.1 SimpleTriggerFactoryBean
经过一番严刑拷打,我们了解到它的身份如下:
-
所在包:org.springframework.scheduling.quartz;
源码位置:
-
作者:Juergen Hoeller
-
出生日期:Spring 3.1
-
性别:Class
-
上层亲属:
- 职业:(下面是英语学习时间)
A Spring FactoryBean for creating a Quartz SimpleTrigger instance, supporting bean-style usage for trigger configuration.
一个用于创建Quartz SimpleTrigger实例的Spring FactoryBean,它支持bean风格的触发器配置用法。
SimpleTrigger(Impl) itself is already a JavaBean but lacks sensible defaults. This class uses the Spring bean name as job name, the Quartz default group (“DEFAULT”) as job group, the current time as start time, and indefinite repetition, if not specified.
SimpleTrigger(Impl)本身已经是JavaBean,但是缺少合理的默认值。此类使用Spring bean名称作为作业名称,使用Quartz默认组(“ DEFAULT”)作为作业组,将当前时间用作开始时间,以及不确定的重复(如果未指定)。
This class will also register the trigger with the job name and group of a given JobDetail. This allows SchedulerFactoryBean to automatically register a trigger for the corresponding JobDetail, instead of registering the JobDetail separately.
此类还将使用给定JobDetail的作业名称和组来注册触发器。这允许SchedulerFactoryBean自动为相应的JobDetail注册触发器,而不是单独注册JobDetail。
以上,出现了一个SimpleTrigger的东东,我们找它出来撩撩:
- 所在包:org.quartz
- 作者:James House, contributions by Lieven Govaerts of Ebitec Nv, Belgium.
- 出生日期:未知
- 性别:interface
- 上层亲属:Trigger
- 工作内容:
A Trigger that is used to fire a Job at a given moment in time, and optionally repeated at a specified interval.
一个触发器,用于在给定的时间触发作业,并且可以选择以指定的间隔重复执行。
还有一个JobDetail又是啥?它是由JobBuilder创建的,用来创建Job实例的接口,那JobBuilder和Job又是啥?算了,这些暂时不解释,附上quartz的官方github,向深入学习的,请自行clone。
说了这么多,是时候展示真正的技术了:
首先,我们定义一个需要执行的任务:
package com.aran.modules.quartz;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @Author Aran
* @Date 2020/7/30 11:38 下午
*/
public class myQuartzJob extends QuartzJobBean {
private Integer timeout;
public void setTimeout(Integer timeout) {
this.timeout = timeout;
}
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println(String.format(Thread.currentThread().getName() + "执行时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
}
}
该类继承了QuartzJobBean,重写了executeInternal方法,该方法体就是定时任务要执行的内容。
定义一个用于定时任务的配置文件[spring-config.xml]:
<?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.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<bean name="job1" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.aran.modules.quartz.myQuartzJob"/>
<property name="jobDataAsMap">
<map>
<entry key="timeout" value="50000"/>
</map>
</property>
</bean>
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<!-- 需要调用的job,ref指向了job1-->
<property name="jobDetail" ref="job1"/>
<!-- 首次执行延迟,单位:毫秒-->
<property name="startDelay" value="2000"/>
<!-- 周期执行间隔,单位:毫秒-->
<property name="repeatInterval" value="5000"/>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="simpleTrigger"/>
</list>
</property>
</bean>
</beans>
虽然我是在web环境下,但测试时没必要通过web方式,所以,我在applicationContext.xml引入spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="spring-config.xml"/>
</beans>
最后,我们在main中引入xml,实现bean的加载:
package com.aran.modules.quartz;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
* @Author Aran
* @Date 2020/7/31 8:52 上午
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new FileSystemXmlApplicationContext(
"web/WEB-INF/applicationContext.xml");
}
}
运行结果如下:
16:01:11.908 [main] INFO org.quartz.core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.3.2) 'org.springframework.scheduling.quartz.SchedulerFactoryBean#0' with instanceId 'NON_CLUSTERED'
Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.
16:01:11.908 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'org.springframework.scheduling.quartz.SchedulerFactoryBean#0' initialized from an externally provided properties instance.
16:01:11.908 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.3.2
16:01:11.909 [main] INFO org.quartz.core.QuartzScheduler - JobFactory set to: org.springframework.scheduling.quartz.AdaptableJobFactory@78047b92
七月 31, 2020 4:01:11 下午 org.springframework.scheduling.quartz.SchedulerFactoryBean startScheduler
信息: Starting Quartz Scheduler now
16:01:11.919 [main] INFO org.quartz.core.QuartzScheduler - Scheduler org.springframework.scheduling.quartz.SchedulerFactoryBean#0_$_NON_CLUSTERED started.
16:01:11.920 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:01:13.785 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:01:13.785 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-1] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-1执行时间:2020-07-31 16:01:13
16:01:18.782 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-2] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-2执行时间:2020-07-31 16:01:18
16:01:18.783 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:01:23.783 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:01:23.790 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-3] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-3执行时间:2020-07-31 16:01:23
16:01:28.778 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:01:28.780 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-4] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-4执行时间:2020-07-31 16:01:28
16:01:33.782 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:01:33.782 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-5] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-5执行时间:2020-07-31 16:01:33
16:01:38.782 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:01:38.782 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-6] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-6执行时间:2020-07-31 16:01:38
16:01:43.787 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:01:43.787 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-7] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-7执行时间:2020-07-31 16:01:43
16:01:48.781 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:01:48.781 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-8] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-8执行时间:2020-07-31 16:01:48
16:01:53.782 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:01:53.782 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-9] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-9执行时间:2020-07-31 16:01:53
16:01:58.781 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:01:58.781 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-10] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-10执行时间:2020-07-31 16:01:58
16:02:03.782 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-1] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
16:02:03.782 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-1执行时间:2020-07-31 16:02:03
3.1.2 CronTriggerFactoryBean
同样,我们还是了解一下它的身份信息:
- 所在包:org.springframework.scheduling.quartz;
- 作者:Juergen Hoeller
- 出生日期:spring 3.1
- 性别:Class
- 上层亲属关系:
- 工作内容:
A Spring FactoryBean for creating a Quartz CronTrigger instance, supporting bean-style usage for trigger configuration.
一个用于创建Quartz CronTrigger实例的Spring FactoryBean,支持Bean风格的触发器配置使用。
CronTrigger(Impl) itself is already a JavaBean but lacks sensible defaults. This class uses the Spring bean name as job name, the Quartz default group (“DEFAULT”) as job group, the current time as start time, and indefinite repetition, if not specified.
CronTrigger(Impl)本身已经是JavaBean,但是缺少明智的默认值。此类使用Spring bean名称作为作业名称,使用Quartz默认组(“ DEFAULT”)作为作业组,将当前时间用作开始时间,以及不确定的重复(如果未指定)。
This class will also register the trigger with the job name and group of a given JobDetail. This allows SchedulerFactoryBean to automatically register a trigger for the corresponding JobDetail, instead of registering the JobDetail separately.
此类还将使用给定JobDetail的作业名称和组来注册触发器。这允许SchedulerFactoryBean自动为相应的JobDetail注册触发器,而不是单独注册JobDetail。
同样,CronTrigger也是一个触发器,此处不再赘述。
和上面的例子一样,我们只需要在xml中动一下手脚就可以了:
<?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.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<bean name="job1" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.aran.modules.quartz.myQuartzJob"/>
<property name="jobDataAsMap">
<map>
<entry key="timeout" value="50000"/>
</map>
</property>
</bean>
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<!-- 需要调用的job,ref指向了job1-->
<property name="jobDetail" ref="job1"/>
<!-- 首次执行延迟,单位:毫秒-->
<property name="startDelay" value="2000"/>
<!-- 周期执行间隔,单位:毫秒-->
<property name="repeatInterval" value="5000"/>
</bean>
<!-- 调度触发器 -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="job1"/>
<property name="cronExpression" value="0/5 * * * * ?"/>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger"/>
</list>
</property>
</bean>
</beans>
我们设置的是每5秒执行一次:
/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/bin/java -Dvisualvm.id=28525250453841 "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=59457:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/tools.jar:/Users/aran/IdeaProjects/Spring-examples/out/production/spring-examples:/Users/aran/IdeaProjects/Spring-examples/lib/spring-instrument-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-aspects-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-jms-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-beans-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-expression-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-oxm-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-context-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-jdbc-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/commons-logging-1.2.jar:/Users/aran/IdeaProjects/Spring-examples/lib/aopalliance-1.0.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-context-support-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-tx-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-aop-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-orm-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-messaging-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-test-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-core-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-webmvc-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-web-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-aspects/5.2.1.RELEASE/spring-security-aspects-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-messaging/5.2.1.RELEASE/spring-security-messaging-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-ldap/5.2.1.RELEASE/spring-security-ldap-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-cas/5.2.1.RELEASE/spring-security-cas-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-oauth2-resource-server/5.2.1.RELEASE/spring-security-oauth2-resource-server-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-remoting/5.2.1.RELEASE/spring-security-remoting-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-taglibs/5.2.1.RELEASE/spring-security-taglibs-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-openid/5.2.1.RELEASE/spring-security-openid-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-oauth2-core/5.2.1.RELEASE/spring-security-oauth2-core-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-test/5.2.1.RELEASE/spring-security-test-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-crypto/5.2.1.RELEASE/spring-security-crypto-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-acl/5.2.1.RELEASE/spring-security-acl-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-web/5.2.1.RELEASE/spring-security-web-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-core/5.2.1.RELEASE/spring-security-core-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-security-config/5.2.1.RELEASE/spring-security-config-5.2.1.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-ws.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-data-jpa/2.2.4.RELEASE/spring-data-jpa-2.2.4.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-data-commons/2.2.4.RELEASE/spring-data-commons-2.2.4.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-binding-2.4.0.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-js-2.4.0.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-faces-2.4.0.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-js-resources-2.4.0.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-webflow-2.4.0.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-batch-infrastructure-2.2.6.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-batch-core-2.2.6.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-event/5.2.3.RELEASE/spring-integration-event-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-ftp/5.2.3.RELEASE/spring-integration-ftp-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-feed/5.2.3.RELEASE/spring-integration-feed-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-groovy/5.2.3.RELEASE/spring-integration-groovy-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-gemfire/5.2.3.RELEASE/spring-integration-gemfire-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-http/5.2.3.RELEASE/spring-integration-http-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-amqp/5.2.3.RELEASE/spring-integration-amqp-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-jdbc/5.2.3.RELEASE/spring-integration-jdbc-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-jmx/5.2.3.RELEASE/spring-integration-jmx-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-jpa/5.2.3.RELEASE/spring-integration-jpa-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-mongodb/5.2.3.RELEASE/spring-integration-mongodb-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-mqtt/5.2.3.RELEASE/spring-integration-mqtt-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-rmi/5.2.3.RELEASE/spring-integration-rmi-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-mail/5.2.3.RELEASE/spring-integration-mail-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-redis/5.2.3.RELEASE/spring-integration-redis-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-scripting/5.2.3.RELEASE/spring-integration-scripting-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-stream/5.2.3.RELEASE/spring-integration-stream-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-syslog/5.2.3.RELEASE/spring-integration-syslog-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-test/5.2.3.RELEASE/spring-integration-test-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-security/5.2.3.RELEASE/spring-integration-security-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-sftp/5.2.3.RELEASE/spring-integration-sftp-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-twitter/5.0.9.RELEASE/spring-integration-twitter-5.0.9.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-ws/5.2.3.RELEASE/spring-integration-ws-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-xml/5.2.3.RELEASE/spring-integration-xml-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-xmpp/5.2.3.RELEASE/spring-integration-xmpp-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-jms/5.2.3.RELEASE/spring-integration-jms-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-ip/5.2.3.RELEASE/spring-integration-ip-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-file/5.2.3.RELEASE/spring-integration-file-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/spring-integration-core/5.2.3.RELEASE/spring-integration-core-5.2.3.RELEASE.jar:/Users/aran/IdeaProjects/Spring-examples/lib/quartz-2.3.2.jar:/Users/aran/IdeaProjects/Spring-examples/lib/slf4j-api-1.7.30.jar:/Users/aran/IdeaProjects/Spring-examples/lib/logback-core-1.2.3.jar:/Users/aran/IdeaProjects/Spring-examples/lib/logback-classic-1.2.3.jar com.aran.modules.quartz.Main
16:43:32.546 [main] INFO org.quartz.impl.StdSchedulerFactory - Using default implementation for ThreadExecutor
16:43:32.563 [main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
16:43:32.563 [main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.3.2 created.
16:43:32.564 [main] INFO org.quartz.simpl.RAMJobStore - RAMJobStore initialized.
16:43:32.565 [main] INFO org.quartz.core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.3.2) 'org.springframework.scheduling.quartz.SchedulerFactoryBean#0' with instanceId 'NON_CLUSTERED'
Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.
16:43:32.565 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'org.springframework.scheduling.quartz.SchedulerFactoryBean#0' initialized from an externally provided properties instance.
16:43:32.565 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.3.2
16:43:32.566 [main] INFO org.quartz.core.QuartzScheduler - JobFactory set to: org.springframework.scheduling.quartz.AdaptableJobFactory@78047b92
七月 31, 2020 4:43:32 下午 org.springframework.scheduling.quartz.SchedulerFactoryBean startScheduler
信息: Starting Quartz Scheduler now
16:43:32.581 [main] INFO org.quartz.core.QuartzScheduler - Scheduler org.springframework.scheduling.quartz.SchedulerFactoryBean#0_$_NON_CLUSTERED started.
16:43:32.582 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:43:35.011 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-1] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
16:43:35.011 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-1执行时间:2020-07-31 16:43:35
16:43:40.008 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-2] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
16:43:40.008 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-2执行时间:2020-07-31 16:43:40
16:43:45.006 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-3] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
16:43:45.006 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-3执行时间:2020-07-31 16:43:45
16:43:50.005 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-4] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
16:43:50.005 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-4执行时间:2020-07-31 16:43:50
16:43:55.001 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-5] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
16:43:55.001 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-5执行时间:2020-07-31 16:43:55
16:44:00.003 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:44:00.003 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-6] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.job1
org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-6执行时间:2020-07-31 16:44:00
cron是一种规则,如果你对它还不是很熟,请参考这篇文章之后,自己试着玩一下
Quartz的使用就暂时介绍到这里,如果你觉得有点复杂,咱接着往下看!
3.2 Spring Task
Spring Task可以视为一个轻量级的Quartz,可通过配置文件或注解两种方式实现:
3.2.1 配置文件方式
我们先定义一个需要执行的任务:
package com.aran.modules.TimerSchedule.springTask;
import org.springframework.stereotype.Service;
/**
* @Author Aran
* @Date 2020/7/31 4:58 下午
*/
@Service
public class TaskJob {
public void job(){
System.out.println("job is active!");
}
}
- 此处@Service 和 @Component当然都可以,见名知意,还是Service好一些
下面,我们在配置文件中对该任务进行扫描:
<task:scheduled-tasks>
<task:scheduled ref="taskJob" method="job" cron="0/3 * * * * ?"/>
</task:scheduled-tasks>
<context:component-scan base-package=" com.aran.modules.TimerSchedule.springTask " />
此处我们将其定义为每3秒执行一次,ref为需要扫描的类,methods为执行的方法,cron为执行策略,当然,component-scan进行组件扫描
好了,运行一下main:
执行时间:2020-07-31 17:10:48
执行时间:2020-07-31 17:10:51
执行时间:2020-07-31 17:10:54
执行时间:2020-07-31 17:10:57
执行时间:2020-07-31 17:11:00
执行时间:2020-07-31 17:11:03
执行时间:2020-07-31 17:11:06
执行时间:2020-07-31 17:11:09
执行时间:2020-07-31 17:11:12
执行时间:2020-07-31 17:11:15
执行时间:2020-07-31 17:11:18
执行时间:2020-07-31 17:11:21
执行时间:2020-07-31 17:11:24
执行时间:2020-07-31 17:11:27
执行时间:2020-07-31 17:11:30
执行时间:2020-07-31 17:11:33
执行时间:2020-07-31 17:11:36
执行时间:2020-07-31 17:11:39
执行时间:2020-07-31 17:11:42
执行时间:2020-07-31 17:11:45
执行时间:2020-07-31 17:11:48
执行时间:2020-07-31 17:11:51
执行时间:2020-07-31 17:11:54
执行时间:2020-07-31 17:11:57
执行时间:2020-07-31 17:12:00
执行时间:2020-07-31 17:12:03
3.2.2 注解方式
一个@Scheduled解决所有问题:
我们先看下@Scheduled的源码
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.scheduling.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
/**
* Annotation that marks a method to be scheduled. Exactly one of the
* {@link #cron}, {@link #fixedDelay}, or {@link #fixedRate} attributes must be
* specified.
* 标记要调度的方法的注释。
* 必须指定{@link #cron},{@ link #fixedDelay}或{@link #fixedRate}其中一个属性。
*
*
* <p>The annotated method must expect no arguments. It will typically have
* a {@code void} return type; if not, the returned value will be ignored
* when called through the scheduler.
*带注释的方法必须不包含任何参数。它通常具有{@code void}返回类型;如果不是,则通过调度程序调 用时将忽略返回的值。
* <p>Purocessing of {@code @Scheduled} annotations is performed by
* registering a {@link ScheduledAnnotationBeanPostProcessor}. This can be
* done manually or, more conveniently, through the {@code <task:annotation-driven/>}
* element or @{@link EnableScheduling} annotation.
*{@code @Scheduled}注解由注册{@link ScheduledAnnotationBeanPostProcessor}进行处理。可以手动完成此操作,也可以通过{@code <task:annotation-driven />}元素或@ {@ link EnableScheduling}注解更方便地完成此操作。
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
* <em>composed annotations</em> with attribute overrides.
*<p>此注释可以用作<em>元注释</ em>来创建自定义
* 具有属性覆盖的<em>组成的注释</ em>。
* @author Mark Fisher
* @author Juergen Hoeller
* @author Dave Syer
* @author Chris Beams
* @since 3.0
* @see EnableScheduling
* @see ScheduledAnnotationBeanPostProcessor
* @see Schedules
*/
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {
/**
* A special cron expression value that indicates a disabled trigger: {@value}.
* <p>This is primarily meant for use with <code>${...}</code> placeholders,
* allowing for external disabling of corresponding scheduled methods.
* @since 5.1
* @see ScheduledTaskRegistrar#CRON_DISABLED
*/
String CRON_DISABLED = ScheduledTaskRegistrar.CRON_DISABLED;
/**
* A cron-like expression, extending the usual UN*X definition to include triggers
* on the second, minute, hour, day of month, month, and day of week.
* <p>For example, {@code "0 * * * * MON-FRI"} means once per minute on weekdays
* (at the top of the minute - the 0th second).
* <p>The fields read from left to right are interpreted as follows.
* <ul>
* <li>second</li>
* <li>minute</li>
* <li>hour</li>
* <li>day of month</li>
* <li>month</li>
* <li>day of week</li>
* </ul>
* <p>The special value {@link #CRON_DISABLED "-"} indicates a disabled cron
* trigger, primarily meant for externally specified values resolved by a
* <code>${...}</code> placeholder.
* @return an expression that can be parsed to a cron schedule
* @see org.springframework.scheduling.support.CronSequenceGenerator
* 一个cron表达式
*/
String cron() default "";
/**
* A time zone for which the cron expression will be resolved. By default, this
* attribute is the empty String (i.e. the server's local time zone will be used).
* @return a zone id accepted by {@link java.util.TimeZone#getTimeZone(String)},
* or an empty String to indicate the server's default time zone
* @since 4.0
* @see org.springframework.scheduling.support.CronTrigger#CronTrigger(String, java.util.TimeZone)
* @see java.util.TimeZone
* 一个时间区
*/
String zone() default "";
/**
* Execute the annotated method with a fixed period in milliseconds between the
* end of the last invocation and the start of the next.
* @return the delay in milliseconds
* 本次开始与上次结束执行的时间间隔,单位:毫秒
*/
long fixedDelay() default -1;
/**
* Execute the annotated method with a fixed period in milliseconds between the
* end of the last invocation and the start of the next.
* @return the delay in milliseconds as a String value, e.g. a placeholder
* or a {@link java.time.Duration#parse java.time.Duration} compliant value
* @since 3.2.2
* 字符串形式
*/
String fixedDelayString() default "";
/**
* Execute the annotated method with a fixed period in milliseconds between
* invocations.
* @return the period in milliseconds
* 按一定的速率执行
*/
long fixedRate() default -1;
/**
* Execute the annotated method with a fixed period in milliseconds between
* invocations.
* @return the period in milliseconds as a String value, e.g. a placeholder
* or a {@link java.time.Duration#parse java.time.Duration} compliant value
* @since 3.2.2
* 字符串形式
*/
String fixedRateString() default "";
/**
* Number of milliseconds to delay before the first execution of a
* {@link #fixedRate} or {@link #fixedDelay} task.
* @return the initial delay in milliseconds
* @since 3.2
* 初始延迟
*/
long initialDelay() default -1;
/**
* Number of milliseconds to delay before the first execution of a
* {@link #fixedRate} or {@link #fixedDelay} task.
* @return the initial delay in milliseconds as a String value, e.g. a placeholder
* or a {@link java.time.Duration#parse java.time.Duration} compliant value
* @since 3.2.2
* 字符串形式
*/
String initialDelayString() default "";
}
开始的时候,我和你一样奇怪,fixedDelay 和 fixedRate到底是啥区别,于是乎,百度一下,你就知道:
@Scheduled注解可以控制方法定时执行,其中有三个参数可选择:
- fixedDelay控制方法执行的间隔时间,是以上一次方法执行完开始算起,如上一次方法执行阻塞住了,那么直到上一次执行完,并间隔给定的时间后,执行下一次。
- fixedRate是按照一定的速率执行,是从上一次方法执行开始的时间算起,如果上一次方法阻塞住了,下一次也是不会执行,但是在阻塞这段时间内累计应该执行的次数,当不再阻塞时,一下子把这些全部执行掉,而后再按照固定速率继续执行。
- cron表达式可以定制化执行任务,但是执行的方式是与fixedDelay相近的,也是会按照上一次方法结束时间开始算起。
好了,我们同样在TaskJob类中定义一个使用注解的定时任务方法:
@Scheduled(cron = "0/3 * * * * ?")
public void annotationJob(){
System.out.println("注解定时任务执行时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
为了更好的验证注解定时任务的执行,我们注解掉配置文件中的相关内容:
此时启动Main,得到:
就说到这吧,以后遇到更好的,更完善的方式,再回来记录!
完整代码地址:spring-examples@github
不管前方的路有多苦,只要走的方向正确,不管多么崎岖不平,都比站在原地更接近幸福。
——宫崎骏