Spring内置定时任务调度@Scheduled使用详解
Spring提供了@Scheduled注解用于定时任务。
一、@Scheduled的基本使用
启用调度支持:@EnableScheduling
可以将@Scheduled注释与触发器元数据一起添加到方法中。例如,以下方法每隔5秒调用一次,并具有固定的延迟,这意味着周期是从前面每次调用的完成时间开始计算的
@Scheduled(fixedDelay=5000)
publicvoiddoSomething(){
//somethingthatshouldexecuteperiodically
}
如果需要固定速率执行,可以更改批注中指定的属性名。以下方法每5秒调用一次(在每次调用的连续开始时间之间计算)
@Scheduled(fixedRate=5000)
publicvoiddoSomething(){
//somethingthatshouldexecuteperiodically
}
对于固定延迟和固定速率任务,可以通过指示在首次执行方法之前要等待的毫秒数来指定初始延迟
@Scheduled(initialDelay=1000,fixedRate=5000)
publicvoiddoSomething(){
//somethingthatshouldexecuteperiodically
}
如果简单的周期性调度不够表达,可以提供cron表达式。例如,以下命令仅在工作日执行:
@Scheduled(cron="*/5****MON-FRI")
publicvoiddoSomething(){
//somethingthatshouldexecuteonweekdaysonly
}
实现SchedulingConfigurer接口,重写configureTasks方法:
@Schedule注解的一个缺点就是其定时时间不能动态更改,它适用于具有固定任务周期的任务,若要修改任务执行周期,只能走“停服务→修改任务执行周期→重启服务”这条路。而基于SchedulingConfigurer接口方式可以做到。SchedulingConfigurer接口可以实现在@Configuration等注解类上。
ScheduledTaskRegistrar类包括以下几个重要方法:
voidaddTriggerTask(Runnabletask,Triggertrigger)
voidaddTriggerTask(TriggerTasktask)
voidaddCronTask(Runnabletask,Stringexpression)
voidaddCronTask(CronTasktask)
voidaddFixedRateTask(Runnabletask,longinterval)
voidaddFixedRateTask(IntervalTasktask)
voidaddFixedDelayTask(Runnabletask,longdelay)
voidaddFixedDelayTask(IntervalTasktask)
具体实现参考如下:
@Component publicclassTestTaskimplementsSchedulingConfigurer{ @Override publicvoidconfigureTasks(ScheduledTaskRegistrartaskRegistrar){ taskRegistrar.addTriggerTask(newRunnable(){ @Override publicvoidrun(){ //定时任务要执行的内容 System.out.println("【开始执行定时任务。。。】"); } },newTrigger(){ @Override publicDatenextExecutionTime(TriggerContexttriggerContext){ //定时任务触发,可修改定时任务的执行周期 Stringcron="00/5***?";//可以将表达式配置在数据库中 CronTriggertrigger=newCronTrigger(cron); DatenextExecDate=trigger.nextExecutionTime(triggerContext); returnnextExecDate; } }); } }
提示:如果在数据库修改时格式出现错误,则定时任务会停止,即使重新修改正确;此时只能重新启动项目才能恢复。
二、使用@Scheduled注意事项
- spring的注解@Scheduled需要写在实现方法上;
- 定时器的任务方法不能有返回值(如果有返回值,spring初始化的时候会告诉你有个错误、需要设定一个proxytargetclass的某个值为true),不能指向任何的参数;
- 如果该方法需要与应用程序上下文的其他对象进行交互,通常是通过依赖注入来实现;
- 实现类上要有组件的注解@Component。
三、使用@Scheduled常见问题
单线程任务丢失,转为异步线程池
默认的ConcurrentTaskScheduler计划执行器采用Executors.newSingleThreadScheduledExecutor()实现单线程的执行器。因此,对同一个调度任务的执行总是同一个线程。如果任务的执行时间超过该任务的下一次执行时间,则会出现任务丢失,跳过该段时间的任务。上述问题有以下解决办法:
采用异步的方式执行调度任务,配置Spring的@EnableAsync,在执行定时任务的方法上标注@Async配置任务执行池,线程池大小n的数量为单个任务执行所需时间/任务执行的间隔时间。如下:
//每30秒执行一次 @Async("taskExecutor") @Scheduled(fixedRate=1000*3) publicvoidreportCurrentTime(){ System.out.println("线程"+Thread.currentThread().getName()+"开始执行定时任务===&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&7&&&====》" +newSimpleDateFormat("yyyy-MM-ddHH:mm:ss").format(newDate())); longstart=System.currentTimeMillis(); }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。