聊一聊Spring中的@Scheduled注解

一、样例

1.1 demo代码

package com.lazy.snail;import org.springframework.stereotype.Component;
import org.springframework.scheduling.annotation.Scheduled;/*** @ClassName MyTask* @Description TODO* @Author lazysnail* @Date 2024/10/29 17:56* @Version 1.0*/
@Component
public class MyTask {@Scheduled(fixedRate = 3 * 1 * 1000)public void doTask() {System.out.println("doTask");}
}
package com.lazy.snail;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;@Configuration
@EnableScheduling
@ComponentScan(basePackages = "com.lazy.snail")
public class AppConfig {}

1.2 demo概述

AppConfig中注解:

  • @Configuration 声明配置类
  • @EnableScheduling 启用Spring的计划任务执行功能
  • @ComponentScan 组件扫描

MyTask中注解

  • @Component 声明组件
  • @Scheduled 标记该方法是一个计划任务

1.3 样例效果

运行结果:

image-20241029224630575

二、源码流程

2.1 容器初始化阶段

  • 内部bean定义信息注册,ConfigurationClassPostProcessor等
  • 主配置类注册,AppConfig类

想了解过程,看此篇第二节

2.2 容器刷新阶段

2.2.1 bean工厂后置处理器处理

​ ConfigurationClassPostProcessor实例化

image-20241029232919898

​ ConfigurationClassPostProcessor处理bean定义信息的注册

image-20241029233108759

2.2.2 主配置类解析

主要关注AppConfig类上@EnableScheduling注解。

// ConfigurationClassParser
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)throws IOException {// @Import注解处理 @EnableScheduling中有@Import(SchedulingConfiguration.class)processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
}
2.2.2.1 @EnableScheduling
2.2.2.1.1 @Import处理

@EnableScheduling中有@Import注解。

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

SchedulingConfiguration源码:

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SchedulingConfiguration {@Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {return new ScheduledAnnotationBeanPostProcessor();}}
2.2.2.1.2 小结

@EnableScheduling通过@Import引入了一个配置类SchedulingConfiguration。

SchedulingConfiguration中的@Bean注解的方法会在后面实例化一个

ScheduledAnnotationBeanPostProcessor。

@EnableScheduling --> ScheduledAnnotationBeanPostProcessor

2.2.3 配置类bean定义信息加载

加载结果:

image-20241029234909623

2.2.4 注册bean后置处理器

实例化ScheduledAnnotationBeanPostProcessor

通过SchedulingConfiguration中的工厂方法scheduledAnnotationProcessor构造ScheduledAnnotationBeanPostProcessor。

image-20241030000639076

2.2.5 单例实例化

主要看带有@Schduled注解方法的MyTask类的实例化过程。

createBeanInstance(构造)和populateBean(属性赋值)跟普通的bean一样。

重点在于initializeBean方法中,bean后置处理器在bean初始化后的应用。

核心是ScheduledAnnotationBeanPostProcessor的postProcessAfterInitialization方法。

// ScheduledAnnotationBeanPostProcessor
public Object postProcessAfterInitialization(Object bean, String beanName) {if (bean instanceof AopInfrastructureBean || bean instanceof TaskScheduler ||bean instanceof ScheduledExecutorService) {// 忽略AOP基础设施类return bean;}Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);if (!this.nonAnnotatedClasses.contains(targetClass) &&AnnotationUtils.isCandidateClass(targetClass, Arrays.asList(Scheduled.class, Schedules.class))) {// 找被@Scheduled注解的方法// targetClass:MyTaskMap<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,(MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> {Set<Scheduled> scheduledAnnotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);return (!scheduledAnnotations.isEmpty() ? scheduledAnnotations : null);});if (annotatedMethods.isEmpty()) {this.nonAnnotatedClasses.add(targetClass);if (logger.isTraceEnabled()) {logger.trace("No @Scheduled annotations found on bean class: " + targetClass);}} else {// 遍历处理方法annotatedMethods.forEach((method, scheduledAnnotations) ->scheduledAnnotations.forEach(scheduled -> processScheduled(scheduled, method, bean)));if (logger.isTraceEnabled()) {logger.trace(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName +"': " + annotatedMethods);}}}return bean;
}protected void processScheduled(Scheduled scheduled, Method method, Object bean) {try {// 创建一个runnable// bean:MyTask method:doTask()Runnable runnable = 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 fixedRate = convertToMillis(scheduled.fixedRate(), scheduled.timeUnit());if (fixedRate >= 0) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;// 新增一个ScheduledTask添加到fixedRateTasks// 同时新增至Set<ScheduledTask>集合中tasks.add(this.registrar.scheduleFixedRateTask(new FixedRateTask(runnable, fixedRate, initialDelay)));}// 省略部分代码...} catch (IllegalArgumentException ex) {throw new IllegalStateException("Encountered invalid @Scheduled method '" + method.getName() + "': " + ex.getMessage());}
}

三、总结

1. 注解解析

当你使用@Scheduled时,Spring会通过反射机制解析这个注解。具体步骤如下:

  • 注解的定义@Scheduled注解有几个重要的属性,比如fixedRatefixedDelaycron。在上述例子中,我们使用了fixedRate
  • 元注解@Scheduled是一个复合注解,可以使用@Target@Retention来定义它的目标和生命周期。

2. 容器的初始化与实例化

在Spring应用程序启动时,容器会执行以下步骤来初始化和实例化带有@Scheduled注解的组件:

  • 扫描组件:通过@ComponentScan注解,Spring会扫描指定包中的类,寻找带有@Scheduled注解的组件。
  • Bean的注册:找到的组件会被注册到ApplicationContext中,成为一个Spring Bean。
  • ScheduledAnnotationBeanPostProcessor:这是一个后处理器,它会在初始化Bean时处理@Scheduled注解。它的postProcessBeforeInitialization方法会查找所有的@Scheduled注解并进行解析。

3. 任务的调度

任务的调度通过ScheduledAnnotationBeanPostProcessor来完成:

  • 任务计划:该后处理器在处理@Scheduled注解时,会创建ScheduledTask对象,使用Spring的TaskScheduler来安排任务。
  • 使用Scheduler:Spring提供了多种调度器,如ConcurrentTaskSchedulerThreadPoolTaskScheduler。这些调度器负责实际的任务执行。
  • 执行任务:当达到预定的时间(例如,每5秒),调度器会调用performTask()方法,执行定时任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/3707.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

如何高效集成每刻与金蝶云星空的报销单数据

每刻报销单集成到金蝶云星空的技术实现 在企业日常运营中&#xff0c;费用报销和付款申请是两个至关重要的环节。为了提升数据处理效率和准确性&#xff0c;我们采用了轻易云数据集成平台&#xff0c;将每刻系统中的报销单数据无缝对接到金蝶云星空的付款申请单中。本案例将详…

使用量化分析微信小程序工具“梦想兔企业智能风险分析助手”日常操作日记-3-预制菜-惠发食品(603536)

使用量化分析微信小程序工具“梦想兔企业智能风险分析助手”日常操作日记-预制菜。 直接看截图&#xff1a; 1.第一步&#xff1a; 查看产业链&#xff0c;选择查看“中国预制菜行业”&#xff0c;政策支持&#xff0c;热点 查看预制菜产业链 这里我选择了中游-生产商 到行业…

Elasticsearch:如何把 OpenAI 的代码修改为 Azure OpenAI

我们知道除了 OpenAI 提供数据嵌入及 Chat Completion 功能之外&#xff0c;Azure 也提供 OpenAI 类似的服务。这两个都是经常需要的平台。在我们的 Elasticsearh labs 里有很多代码是使用 OpenAI 来完成的&#xff0c;那么我们该如何把它们修改为使用 Azure 所提供的 OpenAI 呢…

软件体系结构

第一章 构件 具有某种功能的 可复用的软件结构单元,为组装服务,可部署,具有规范的接口规约和显式的语境依赖 构件模型 构件模型是对构件本质特征的抽象描述&#xff0c;可以把它想象成一个类的组合&#xff0c;它封装了多个类&#xff0c;并具有一个或多个服务而提供了简单…

基于AI深度学习的中医针灸实训室腹针穴位智能辅助定位系统开发

在中医针灸的传统治疗中&#xff0c;穴位取穴的精确度对于治疗效果至关重要。然而&#xff0c;传统的定位方法&#xff0c;如体表标志法、骨度折量法和指寸法&#xff0c;由于观察角度、个体差异&#xff08;如人体姿态和皮肤纹理&#xff09;以及环境因素的干扰&#xff0c;往…

华硕推出Intel Xeon 6/ Gaudi 3服务器 加速企业AI布局!

(10月23日&#xff0c;台北讯) 华硕服务器新品接力强势助攻&#xff0c;今再推出多款搭载Intel Xeon 6处理器的服务器&#xff0c;包括&#xff1a;多节点的ASUS RS920Q-E12&#xff0c;其兼容适用HPC运算的Intel Xeon 6900系列处理器&#xff1b;以及ASUS RS720Q-E12、RS720-E…

[MySQL#11] 索引底层(2) | B+树 | 索引的CURD | 全文索引

目录 1.B树的特点 索引结构 复盘 其他数据结构的对比 B树与B树总结 聚簇索引与非聚簇索引 辅助索引 2. 索引操作 主键索引 1. 创建主键索引 第一种方式 第二种方式 第三种方式 2. 查询索引 第一种方法 第二种方法 第三种方法 3. 删除索引 删除主键索引 删除…

人工智能基础-opencv-图像处理篇

一.图像预处理 图像翻转 cv2.flip 是 OpenCV 库中的一个函数&#xff0c;用于翻转图像。翻转可以是水平翻转、垂直翻转或同时水平和垂直翻转。这个函数接受两个参数&#xff1a;要翻转的图像和一个指定翻转类型的标志。 img cv2.imread(../images/car2.png) #翻转 0&#xf…

【机器学习】嘿马机器学习(科学计算库)第4篇:Matplotlib,学习目标【附代码文档】

本教程的知识点为&#xff1a;机器学习&#xff08;常用科学计算库的使用&#xff09;基础定位 机器学习概述 机器学习概述 1.5 机器学习算法分类 1 监督学习 机器学习概述 1.7 Azure机器学习模型搭建实验 Azure平台简介 Matplotlib 3.2 基础绘图功能 — 以折线图为例 1 完善原…

平衡二叉树(递归)

给定一个二叉树&#xff0c;判断它是否是 平衡二叉树.平衡二叉树 是指该树所有节点的左右子树的深度相差不超过 1。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,3,3,null,null,4…

Python数据分析案例61——信贷风控评分卡模型(A卡)(scorecardpy 全面解析)

案例背景 虽然在效果上&#xff0c;传统的逻辑回归模型通常不如现代的机器学习模型&#xff0c;但在风控领域&#xff0c;解释性至关重要。逻辑回归的解释性是这些“黑箱”模型所无法比拟的&#xff0c;因此&#xff0c;研究传统的评分卡模型依然是有意义的。 传统的评分卡模型…

Weblogic漏洞复现(Vulhub)

0x00前言 1.docker 安装 Docker的安装_docker安装-CSDN博客 2.docker的镜像 1.可以在阿里云上的容器服务找到镜像源。 2.也可以使用下面的镜像源&#xff0c;时快时慢不稳定。 {"registry-mirrors":["https://docker.registry.cyou","https://d…

【Python环境配置-Step1】PyCharm 2024最新官网下载、安装教程

背景&#xff1a; 1、 步骤&#xff1a; 1、PyCharm 官网下载地址&#xff1a;https://www.jetbrains.com/pycharm/ 2、查看下图红框选中&#xff0c;下载社区版&#xff08;免费&#xff09; 3、&#xff08;查看下图红框选中&#xff09;这里选其他版本 4、这里我下载的…

用vite创建项目

一. vite vue2 1. 全局安装 create-vite npm install -g create-vite 2. 创建项目 进入你想要创建项目的文件夹下 打开 CMD 用 JavaScript create-vite my-vue2-project --template vue 若用 TypeScript 则 create-vite my-vue2-project --template vue-ts 这里的 …

FBX福币交易所A股三大指数小幅低开 稀土永磁板块回调

查查配分析11月5日电 周二,A股三大指数小幅低开。沪指开盘跌0.10%报3306.81点,深证成指开盘跌0.09%报10653.20点,创业板指开盘跌0.05%报2184.90点。 FBX福币凭借用户友好的界面和对透明度的承诺,迅速在加密货币市场中崭露头角,成为广大用户信赖的平台。 来源:同花顺iFinD 盘面…

LeetCode总结-链表

一、遍历链表 1290.二进制链表转整数 2058.找出临界点之间的最小和最大距离 2181.合并零之间的节点 二、删除节点 问&#xff1a;为什么没有修改 dummy&#xff0c;但 dummy.next 却是新链表的头节点&#xff1f;如果删除了 head&#xff0c;那么最后返回的是不是原链表的头…

腐蚀图像分割系统:前端交互展示

腐蚀图像分割系统源码&#xff06;数据集分享 [yolov8-seg-C2f-DySnakeConv&#xff06;yolov8-seg-LSKNet等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI Global Al…

NIM 平台生成式 AI-demo

需要python环境 官网注册&#xff1a;&#xff08;后续调用模型需要秘钥key&#xff09;Try NVIDIA NIM APIs 可以看到有多种模型&#xff1a; 官方案例 1.安装相关依赖&#xff1a; pip install langchain_nvidia_ai_endpoints langchain-community langchain-text-splitt…

欢迎使用Markdown编辑器

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

智慧医疗:AI如何改变传统医疗服务模式?

内容概要 在如今的医疗界&#xff0c;智慧医疗正如一阵旋风&#xff0c;呼啸而来&#xff0c;打破了传统的模式。这一变革的核心&#xff0c;毫无疑问是人工智能。想象一下&#xff0c;一个不需要排队候诊、甚至不需要出门的医生——这就是智能助手的非凡魅力&#xff01;通过…