当前位置:网站首页>@Scheduled注解的坑,我替你踩了
@Scheduled注解的坑,我替你踩了
2022-06-29 23:28:00 【InfoQ】
问题背景
Spring
@Scheduled
Spring
@Scheduled
@Scheduled失效原因分析
@Scheduled
SpringBoot
@Scheduled
@Scheduled

Spring
@Scheduled

ScheduledAnnotationBeanPostProcessor
@Scheduled
BeanPostProcessor
Spring
bean
before
after
bean
Spring
BeanPostProcessor
postProcessAfterInitialization
bean
SpringBoot
ScheduledAnnotationBeanPostProcessor

ScheduledAnnotationBeanPostProcessor
public class ScheduledAnnotationBeanPostProcessor implements MergedBeanDefinitionPostProcessor, DestructionAwareBeanPostProcessor, Ordered, EmbeddedValueResolverAware, BeanNameAware, BeanFactoryAware, ApplicationContextAware, SmartInitializingSingleton, ApplicationListener<ContextRefreshedEvent>, DisposableBean {
...
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof AopInfrastructureBean) {
return bean;
} else {
//(key-1)解析所有Scheduled注解的类
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
if (!this.nonAnnotatedClasses.contains(targetClass)) {
Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass, new MetadataLookup<Set<Scheduled>>() {
public Set<Scheduled> inspect(Method method) {
Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);
return !scheduledMethods.isEmpty() ? scheduledMethods : null;
}
});
if (annotatedMethods.isEmpty()) {
this.nonAnnotatedClasses.add(targetClass);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No @Scheduled annotations found on bean class: " + targetClass);
}
} else {
Iterator var5 = annotatedMethods.entrySet().iterator();
while(var5.hasNext()) {
Entry<Method, Set<Scheduled>> entry = (Entry)var5.next();
Method method = (Method)entry.getKey();
Iterator var8 = ((Set)entry.getValue()).iterator();
while(var8.hasNext()) {
Scheduled scheduled = (Scheduled)var8.next();
//(key-2)处理被注解修饰的类
this.processScheduled(scheduled, method, bean);
}
}
if (this.logger.isDebugEnabled()) {
this.logger.debug(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName + "': " + annotatedMethods);
}
}
}
return bean;
}
}
...
}
@Scheduled
@Schedules
map
key
@Scheduled
@Schedules
key-1``map
processScheduled
protected void processScheduled(Scheduled scheduled, Method method, Object bean) {
try {
Runnable runnable = this.createRunnable(bean, method);
boolean processedSchedule = false;
String errorMessage = "Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required";
Set<ScheduledTask> tasks = new LinkedHashSet(4);
long initialDelay = scheduled.initialDelay();
...
//(key-1)获取注解中对应的scron参数
String cron = scheduled.cron();
if (StringUtils.hasText(cron)) {
String zone = scheduled.zone();
if (this.embeddedValueResolver != null) {
cron = this.embeddedValueResolver.resolveStringValue(cron);
zone = this.embeddedValueResolver.resolveStringValue(zone);
}
if (StringUtils.hasLength(cron)) {
Assert.isTrue(initialDelay == -1L, "'initialDelay' not supported for cron triggers");
processedSchedule = true;
if (!"-".equals(cron)) {
TimeZone timeZone;
if (StringUtils.hasText(zone)) {
timeZone = StringUtils.parseTimeZoneString(zone);
} else {
timeZone = TimeZone.getDefault();
}
//(key-2)添加到任务列表
tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))));
}
}
}
...
Assert.isTrue(processedSchedule, errorMessage);
Map var18 = this.scheduledTasks;
synchronized(this.scheduledTasks) {
Set<ScheduledTask> regTasks = (Set)this.scheduledTasks.computeIfAbsent(bean, (key) -> {
return new LinkedHashSet(4);
});
regTasks.addAll(tasks);
}
} catch (IllegalArgumentException var25) {
throw new IllegalStateException("Encountered invalid @Scheduled method '" + method.getName() + "': " + var25.getMessage());
}
}
CronTask

springboot
public ScheduledTask scheduleCronTask(CronTask task) {
ScheduledTask scheduledTask = this.unresolvedTasks.remove(task);
boolean newTask = false;
if (scheduledTask == null) {
scheduledTask = new ScheduledTask();
newTask = true;
}
if (this.taskScheduler != null) {
scheduledTask.future = this.taskScheduler.schedule(task.getRunnable(), task.getTrigger());
}
else {
addCronTask(task);
this.unresolvedTasks.put(task, scheduledTask);
}
return (newTask ? scheduledTask : null);
}
JVM
JVM
CPU ticks
Spring
Spring
public ScheduledFuture<?> schedule() {
synchronized (this.triggerContextMonitor) {
this.scheduledExecutionTime = this.trigger.nextExecutionTime(this.triggerContext);
if (this.scheduledExecutionTime == null) {
return null;
}
//获取时间差
long initialDelay = this.scheduledExecutionTime.getTime() - System.currentTimeMillis();
this.currentFuture = this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS);
return this;
}
}
@Scheduled
ScheduledThreadPoolExecutor
System.nanoTime
边栏推荐
- Fund valuation, expenses and accounting
- 二叉树的序列化 力扣 297. 二叉树的序列化与反序列化 652. 寻找重复的子树
- 语音信号处理(三):语音信号分析【连续的“模拟信号”--采样、量化、编码-->离散的“数字信号”】
- MetaQ集群安装测试
- Effective self summary of remote communication | community essay solicitation
- 关于二叉树
- Implementation principle of dynamic agent
- 2022 PMP project management examination agile knowledge points (5)
- CE第二次作业
- Wechat applet: (update) cloud development wechat group contacts
猜你喜欢
随机推荐
Remember the process of checking online MySQL deadlock. You should not only know curd, but also know the principle of locking
论文阅读《Large-Scale Direct SLAM with Stereo Cameras》
海外数字身份验证服务商ADVANCE.AI入选EqualOcean《2022品牌出海服务市场研究报告》
動態代理的實現原理
搭建企业级NTP时间服务器
Speech signal processing (III): speech signal analysis [continuous "analog signal" -- Sampling, quantization, coding -- > discrete "digital signal"]
采购数智化爆发在即,支出宝“3+2“体系助力企业打造核心竞争优势
Fund valuation, expenses and accounting
剑指 Offer 13. 机器人的运动范围
Project 1 - buffer pool [cmu 15-445645] notes
Dépannage de l'étiquette: impossible d'ouvrir l'image marquée
二叉搜索树 230. 二叉搜索树中第K小的元素 1038. 从二叉搜索树到更大和树
Status acquisition and control system of on-site express cabinet
声网自研传输层协议 AUT 的落地实践丨Dev for Dev 专栏
Test d'installation du cluster metaq
Cacti关于spine轮询的设置
SYSTEMd debugging
25 interview questions about Apache
数据库-玩转数据-Pgsql 使用UUID做主键
Solr basic operation