Spring内置定时任务调度@Scheduled使用详解
Spring提供了@Scheduled注解用于定时任务。
一、@Scheduled的基本使用
启用调度支持:@EnableScheduling
可以将@Scheduled注释与触发器元数据一起添加到方法中。例如,以下方法每隔5秒调用一次,并具有固定的延迟,这意味着周期是从前面每次调用的完成时间开始计算的
@Scheduled(fixedDelay=5000)public void doSomething() {// something that should execute periodically}
如果需要固定速率执行,可以更改批注中指定的属性名。以下方法每5秒调用一次(在每次调用的连续开始时间之间计算)
@Scheduled(fixedRate=5000)public void doSomething() {// something that should execute periodically}
对于固定延迟和固定速率任务,可以通过指示在首次执行方法之前要等待的毫秒数来指定初始延迟
@Scheduled(initialDelay=1000, fixedRate=5000)public void doSomething() {// something that should execute periodically}
如果简单的周期性调度不够表达,可以提供cron表达式。例如,以下命令仅在工作日执行:
@Scheduled(cron='*/5 * * * * MON-FRI')public void doSomething() {// something that should execute on weekdays only}
实现SchedulingConfigurer接口,重写configureTasks方法:
@Schedule注解的一个缺点就是其定时时间不能动态更改,它适用于具有固定任务周期的任务,若要修改任务执行周期,只能走“停服务→修改任务执行周期→重启服务”这条路。而基于 SchedulingConfigurer 接口方式可以做到。SchedulingConfigurer 接口可以实现在@Configuration等注解类上。
ScheduledTaskRegistrar类包括以下几个重要方法:
void addTriggerTask(Runnable task, Trigger trigger) void addTriggerTask(TriggerTask task)void addCronTask(Runnable task, String expression)void addCronTask(CronTask task)void addFixedRateTask(Runnable task, long interval)void addFixedRateTask(IntervalTask task)void addFixedDelayTask(Runnable task, long delay)void addFixedDelayTask(IntervalTask task)
具体实现参考如下:
@Componentpublic class TestTask implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.addTriggerTask(new Runnable() { @Override public void run() {// 定时任务要执行的内容System.out.println('【开始执行定时任务。。。】'); } }, new Trigger() { @Override public Date nextExecutionTime(TriggerContext triggerContext) {// 定时任务触发,可修改定时任务的执行周期String cron = '0 0/5 * * * ?'; //可以将表达式配置在数据库中CronTrigger trigger = new CronTrigger(cron);Date nextExecDate = trigger.nextExecutionTime(triggerContext);return nextExecDate; } }); }}
提示:如果在数据库修改时格式出现错误,则定时任务会停止,即使重新修改正确;此时只能重新启动项目才能恢复。
二、使用@Scheduled注意事项
spring的注解@Scheduled 需要写在实现方法上; 定时器的任务方法不能有返回值(如果有返回值,spring初始化的时候会告诉你有个错误、需要设定一个proxytargetclass的某个值为true),不能指向任何的参数; 如果该方法需要与应用程序上下文的其他对象进行交互,通常是通过依赖注入来实现; 实现类上要有组件的注解@Component。三、使用@Scheduled常见问题
单线程任务丢失,转为异步线程池
默认的 ConcurrentTaskScheduler 计划执行器采用Executors.newSingleThreadScheduledExecutor() 实现单线程的执行器。因此,对同一个调度任务的执行总是同一个线程。如果任务的执行时间超过该任务的下一次执行时间,则会出现任务丢失,跳过该段时间的任务。上述问题有以下解决办法:
采用异步的方式执行调度任务,配置 Spring 的 @EnableAsync,在执行定时任务的方法上标注 @Async配置任务执行池,线程池大小 n 的数量为 单个任务执行所需时间 / 任务执行的间隔时间。如下:
//每30秒执行一次@Async('taskExecutor')@Scheduled(fixedRate = 1000 * 3)public void reportCurrentTime(){ System.out.println ('线程' + Thread.currentThread().getName() + '开始执行定时任务===&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&7&&&====》' + new SimpleDateFormat('yyyy-MM-dd HH:mm:ss').format(new Date())); long start = System.currentTimeMillis();}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持好吧啦网。
相关文章: