日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

spring源码分析之定时任务Scheduled注解

發(fā)布時間:2025/4/5 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring源码分析之定时任务Scheduled注解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1. @Scheduled 可以將一個方法標(biāo)識為可定時執(zhí)行的。但必須指明cron(),fixedDelay(),或者fixedRate()屬性。

注解的方法必須是無輸入?yún)?shù)并返回空類型void的。

@Scheduled注解由注冊的ScheduledAnnotationBeanPostProcessor來處理,該processor可以通過手動來注冊,更方面的方式是通過<task:annotation-driven/>或者@EnableScheduling來注冊。@EnableScheduling可以注冊的原理是什么呢?先看定義:

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(SchedulingConfiguration.class) @Documented public @interface EnableScheduling {}

可以看到@EnableScheduling的實(shí)現(xiàn)由SchedulingConfiguration來完成。

@Configuration public class SchedulingConfiguration {@Bean(name = AnnotationConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {return new ScheduledAnnotationBeanPostProcessor();}}

從上述代碼可以看出,SchedulingConfiguration注冊了一個ScheduledAnnotationBeanPostProcessor。

來看一下ScheduledAnnotationBeanPostProcessor來如何處理定時任務(wù)的?

protected void processScheduled(Scheduled scheduled, Method method, Object bean) {try {Assert.isTrue(void.class.equals(method.getReturnType()),"Only void-returning methods may be annotated with @Scheduled");Assert.isTrue(method.getParameterTypes().length == 0,"Only no-arg methods may be annotated with @Scheduled");if (AopUtils.isJdkDynamicProxy(bean)) {try {// Found a @Scheduled method on the target class for this JDK proxy ->// is it also present on the proxy itself?method = bean.getClass().getMethod(method.getName(), method.getParameterTypes());}catch (SecurityException ex) {ReflectionUtils.handleReflectionException(ex);}catch (NoSuchMethodException ex) {throw new IllegalStateException(String.format("@Scheduled method '%s' found on bean target class '%s' but not " +"found in any interface(s) for a dynamic proxy. Either pull the " +"method up to a declared interface or switch to subclass (CGLIB) " +"proxies by setting proxy-target-class/proxyTargetClass to 'true'",method.getName(), method.getDeclaringClass().getSimpleName()));}}else if (AopUtils.isCglibProxy(bean)) {// Common problem: private methods end up in the proxy instance, not getting delegated.if (Modifier.isPrivate(method.getModifiers())) {LogFactory.getLog(ScheduledAnnotationBeanPostProcessor.class).warn(String.format("@Scheduled method '%s' found on CGLIB proxy for target class '%s' but cannot " +"be delegated to target bean. Switch its visibility to package or protected.",method.getName(), method.getDeclaringClass().getSimpleName()));}}Runnable runnable = new ScheduledMethodRunnable(bean, method);boolean processedSchedule = false;String errorMessage ="Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required";// Determine initial delaylong initialDelay = scheduled.initialDelay();String initialDelayString = scheduled.initialDelayString();if (StringUtils.hasText(initialDelayString)) {Assert.isTrue(initialDelay < 0, "Specify 'initialDelay' or 'initialDelayString', not both");if (this.embeddedValueResolver != null) {initialDelayString = this.embeddedValueResolver.resolveStringValue(initialDelayString);}try {initialDelay = Integer.parseInt(initialDelayString);}catch (NumberFormatException ex) {throw new IllegalArgumentException("Invalid initialDelayString value \"" + initialDelayString + "\" - cannot parse into integer");}}// Check cron expressionString cron = scheduled.cron();if (StringUtils.hasText(cron)) {Assert.isTrue(initialDelay == -1, "'initialDelay' not supported for cron triggers");processedSchedule = true;String zone = scheduled.zone();if (this.embeddedValueResolver != null) {cron = this.embeddedValueResolver.resolveStringValue(cron);zone = this.embeddedValueResolver.resolveStringValue(zone);}TimeZone timeZone;if (StringUtils.hasText(zone)) {timeZone = StringUtils.parseTimeZoneString(zone);}else {timeZone = TimeZone.getDefault();}this.registrar.addCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone)));}// At this point we don't need to differentiate between initial delay set or not anymoreif (initialDelay < 0) {initialDelay = 0;}// Check fixed delaylong fixedDelay = scheduled.fixedDelay();if (fixedDelay >= 0) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;this.registrar.addFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay));}String fixedDelayString = scheduled.fixedDelayString();if (StringUtils.hasText(fixedDelayString)) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;if (this.embeddedValueResolver != null) {fixedDelayString = this.embeddedValueResolver.resolveStringValue(fixedDelayString);}try {fixedDelay = Integer.parseInt(fixedDelayString);}catch (NumberFormatException ex) {throw new IllegalArgumentException("Invalid fixedDelayString value \"" + fixedDelayString + "\" - cannot parse into integer");}this.registrar.addFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay));}// Check fixed ratelong fixedRate = scheduled.fixedRate();if (fixedRate >= 0) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;this.registrar.addFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay));}String fixedRateString = scheduled.fixedRateString();if (StringUtils.hasText(fixedRateString)) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;if (this.embeddedValueResolver != null) {fixedRateString = this.embeddedValueResolver.resolveStringValue(fixedRateString);}try {fixedRate = Integer.parseInt(fixedRateString);}catch (NumberFormatException ex) {throw new IllegalArgumentException("Invalid fixedRateString value \"" + fixedRateString + "\" - cannot parse into integer");}this.registrar.addFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay));}// Check whether we had any attribute set Assert.isTrue(processedSchedule, errorMessage);}catch (IllegalArgumentException ex) {throw new IllegalStateException("Encountered invalid @Scheduled method '" + method.getName() + "': " + ex.getMessage());}}

從上面的代碼可以看出:@Scheduled有三個屬性,分別是:

cron expression fixedDelay fixedRate

根據(jù)這些屬性的不同,都加入到ScheduledTaskRegistrar來管理定時任務(wù):

/*** Schedule all registered tasks against the underlying {@linkplain* #setTaskScheduler(TaskScheduler) task scheduler}.*/protected void scheduleTasks() {long now = System.currentTimeMillis();if (this.taskScheduler == null) {this.localExecutor = Executors.newSingleThreadScheduledExecutor();this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);}if (this.triggerTasks != null) {for (TriggerTask task : this.triggerTasks) {this.scheduledFutures.add(this.taskScheduler.schedule(task.getRunnable(), task.getTrigger()));}}if (this.cronTasks != null) {for (CronTask task : this.cronTasks) {this.scheduledFutures.add(this.taskScheduler.schedule(task.getRunnable(), task.getTrigger()));}}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()));}}}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()));}}}}

從上面看出:

3種不同屬性的task均由quartz的taskScheduler的不同方法來完成,

scheduleWithFixedDelay, scheduleAtFixedRate, schedule

即最終的實(shí)現(xiàn)由TaskScheduler來完成定時任務(wù)。

?

轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/p/5680088.html

總結(jié)

以上是生活随笔為你收集整理的spring源码分析之定时任务Scheduled注解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。