Spring定时任务注解说明
设定明确的目标并分解大任务 #生活技巧# #时间管理技巧# #任务优先级排序#
一、注解说明。
Spring 自带的定时任务执行@Scheduled注解,可以定时的、周期性的执行一些任务。查看@Scheduled的注解可以看到有以下三种:
1.1 String cron() default “” ;
//定义一个按时间执行的定时任务,在每天1:00执行一次。 @Scheduled(cron = "0 0 1* * ?") public void run() { //执行代码 }12345
参数说明:
"0 0 12 * * ?" 每天中午十二点触发 "0 15 10 ? * *" 每天早上10:15触发 "0 15 10 * * ?" 每天早上10:15触发 "0 15 10 * * ? *" 每天早上10:15触发 "0 15 10 * * ? 2005" 2005年的每天早上10:15触发 "0 * 14 * * ?" 每天从下午2点开始到2点59分每分钟一次触发 "0 0/5 14 * * ?" 每天从下午2点开始到2:55分结束每5分钟一次触发 "0 0/5 14,18 * * ?" 每天的下午2点至2:55和6点至6点55分两个时间段内每5分钟一次触发 "0 0-5 14 * * ?" 每天14:00至14:05每分钟一次触发 "0 10,44 14 ? 3 WED" 三月的每周三的14:10和14:44触发 "0 15 10 ? * MON-FRI" 每个周一、周二、周三、周四、周五的10:15触发 1234567891011
1.2 long fixedDelay() default -1;
//定义一个按一定频率执行的定时任务,每隔1分钟执行一次,延迟1秒执行 @Scheduled(fixedRate = 1000 * 60,initialDelay = 1000) public void run() { //执行代码 }12345
1.3 long fixedRate() default -1;
//定义一个按一定频率执行的定时任务,每隔2分钟执行一次 @Scheduled(fixedRate = 1000 * 120) public void run() { //执行代码 }12345
二、@Scheduled 执行原理说明:
简要介绍:spring在初始化bean后,通过“postProcessAfterInitialization”拦截到所有的用到“@Scheduled”注解的方法,并解析相应的的注解参数,放入“定时任务列表”等待后续处理;之后再“定时任务列表”中统一执行相应的定时任务。
2.1 依次加载所有的实现 Scheduled 注解的类方法。(具体查看 spring-context jar包)说明:
ScheduledAnnotationBeanPostProcessor继承BeanPostProcessor。 public Object postProcessAfterInitialization (final Object bean, String beanName ) { final Class<?> targetClass = AopUtils.getTargetClass(bean); ReflectionUtils. doWithMethods(targetClass, new MethodCallback() { public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { Scheduled annotation = AnnotationUtils.getAnnotation(method, Scheduled.class); if (annotation != null) { // 此处省略条件判断说明 Runnable runnable = new ScheduledMethodRunnable(bean , method ); boolean processedSchedule = false; String errorMessage = "Exactly one of 'cron', 'fixedDelay', or 'fixedRate' is required."; String cron = annotation.cron(); if (!"" .equals(cron )) { processedSchedule = true ; if (embeddedValueResolver != null) { cron = embeddedValueResolver.resolveStringValue(cron ); } cronTasks.put(runnable , cron); } long fixedDelay = annotation.fixedDelay(); if (fixedDelay >= 0) { Assert. isTrue(!processedSchedule, errorMessage); processedSchedule = true ; fixedDelayTasks.put(runnable , fixedDelay ); } long fixedRate = annotation.fixedRate(); if (fixedRate >= 0) { Assert. isTrue(!processedSchedule, errorMessage); processedSchedule = true ; fixedRateTasks.put(runnable , fixedRate); } Assert. isTrue(processedSchedule, errorMessage); } } }); return bean ; }
12345678910111213141516171819202122232425262728293031323334353637从这段代码中我们可以发现任务为顺序执行,先执行cron,之后再执行fixedRate。
2.2 将对应类型的定时器放入相应的“定时任务列表”中,获取scheduled类参数,之后根据参数类型、相应的延时时间、对应的时区放入不同的任务列表中
protected void processScheduled(Scheduled scheduled, Method method, Object bean) { //获取corn类型 String cron = scheduled.cron(); if (StringUtils.hasText(cron)) { Assert.isTrue(initialDelay == -1, "'initialDelay' not supported for cron triggers"); processedSchedule = true; String zone = scheduled.zone(); //放入cron任务列表中(不执行) this.registrar.addCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))); } //执行频率类型(long类型) long fixedRate = scheduled.fixedRate(); String fixedDelayString = scheduled.fixedDelayString(); if (fixedRate >= 0) { Assert.isTrue(!processedSchedule, errorMessage); processedSchedule = true; //放入FixedRate任务列表中(不执行)(registrar为ScheduledTaskRegistrar) this.registrar.addFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay)); } //执行频率类型(字符串类型,不接收参数计算如:600*20) String fixedRateString = scheduled.fixedRateString(); if (StringUtils.hasText(fixedRateString)) { Assert.isTrue(!processedSchedule, errorMessage); processedSchedule = true; if (this.embeddedValueResolver != null) { fixedRateString = this.embeddedValueResolver.resolveStringValue(fixedRateString); } fixedRate = Long.parseLong(fixedRateString); //放入FixedRate任务列表中(不执行) this.registrar.addFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay)); } } return bean; }
123456789101112131415161718192021222324252627282930313233342.3:执行相应的定时任务。
说明:定时任务先执行corn,判断定时任务的执行时间,计算出相应的下次执行时间,放入线程中,到相应的时间后进行执行。之后执行按“频率”(fixedRate)执行的定时任务,直到所有任务执行结束。
protected void scheduleTasks() { //顺序执行相应的Cron if (this.cronTasks != null) { for (CronTask task : this.cronTasks) { this.scheduledFutures.add(this.taskScheduler.schedule( task.getRunnable(), task.getTrigger())); } } //顺序执行所有的“fixedRate”定时任务(无延迟,也就是说initialDelay参数为空),因为无延迟,所以定时任务会直接执行一次,执行任务完成后,会将下次执行任务的时间放入delayedExecute中等待下次执行。 if (this.fixedRateTasks != null) { for (IntervalTask task : this.fixedRateTasks) { if (task.getInitialDelay() > 0) { Date startTime = new Date(now + task.getInitialDelay()); this.scheduledFutures.add(this.taskScheduler.scheduleAtFixedRate( task.getRunnable(), startTime, task.getInterval())); } else { this.scheduledFutures.add(this.taskScheduler.scheduleAtFixedRate( task.getRunnable(), task.getInterval())); } } } //顺序执行所有的“fixedRate”定时任务(有延迟,也就是说initialDelay参数不为空) if (this.fixedDelayTasks != null) { for (IntervalTask task : this.fixedDelayTasks) { if (task.getInitialDelay() > 0) { Date startTime = new Date(now + task.getInitialDelay()); this.scheduledFutures.add(this.taskScheduler.scheduleWithFixedDelay( task.getRunnable(), startTime, task.getInterval())); } else { this.scheduledFutures.add(this.taskScheduler.scheduleWithFixedDelay( task.getRunnable(), task.getInterval())); } } } }
123456789101112131415161718192021222324252627282930313233343536372.4 接下来看下定时任务run(extends自Runnable接口)方法:
//说明:每次执行定时任务结束后,会先设置下下次定时任务的执行时间,以此来确认下次任务的执行时间。
public void run() { boolean periodic = isPeriodic(); if (!canRunInCurrentRunState(periodic)) cancel(false); else if (!periodic) ScheduledFutureTask.super.run(); else if (ScheduledFutureTask.super.runAndReset()) { setNextRunTime(); reExecutePeriodic(outerTask); } }1234567891011
备注1:从上面的代码可以看出,如果多个定时任务定义的是同一个时间,那么也是顺序执行的,会根据程序加载Scheduled方法的先后来执行。
但是如果某个定时任务执行未完成会出现什么现象呢?
答:此任务一直无法执行完成,无法设置下次任务执行时间,之后会导致此任务后面的所有定时任务无法继续执行,也就会出现所有的定时任务“失效”现象。
所以应用springBoot中定时任务的方法中,一定不要出现“死循环”、“http持续等待无响应”现象,否则会导致定时任务程序无法正常。再就是非特殊需求情况下可以把定时任务“分散”下。
网址:Spring定时任务注解说明 https://www.yuejiaxmz.com/news/view/291553
相关内容
使用Spring@Scheduled(cron = “0 0/10 * * * ?”) 实现定时任务Spring Boot 事务的简单使用
Spring 注解使用笔记(一)
工作任务管理系说明.doc
运维(10) 解决Nacos服务注册使用Docker容器内网ip问题(指定注册ip或
Spring中文件的上传下载
基于Spring Boot+Vue的校园二手交易平台
timetask定时任务
基于Spring Boot + Vue + MySQL的公益旧物捐赠系统
为什么越来越多的开发者选择使用Spring Boot?