分布式之任务调度学习二

news2024/11/15 10:59:57

4 Quartz 集成到 Spring

Spring-quartz 工程
Spring 在 spring-context-support.jar 中直接提供了对 Quartz 的支持
在这里插入图片描述
可以在配置文件中把 JobDetail、Trigger、Scheduler 定义成 Bean。

4.1 定义 Job

<bean name="myJob1" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
	<property name="name" value="my_job_1"/>
	<property name="group" value="my_group"/>
	<property name="jobClass" value="com.gupaoedu.quartz.MyJob1"/>
	<property name="durability" value="true"/>
</bean>

4.2 定义 Trigger

<bean name="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
	<property name="name" value="my_trigger_1"/>
	<property name="group" value="my_group"/>
	<property name="jobDetail" ref="myJob1"/>
	<property name="startDelay" value="1000"/>
	<property name="repeatInterval" value="5000"/>
	<property name="repeatCount" value="2"/>
</bean>

4.3 定义 Scheduler

<bean name="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
	<property name="triggers">
		<list>
			<ref bean="simpleTrigger"/>
			<ref bean="cronTrigger"/>
		</list>
	</property>
</bean>

既然可以在配置文件配置,当然也可以用@Bean 注解配置。在配置类上加上@Configuration 让 Spring 读取到。

public class QuartzConfig {
	@Bean
	public JobDetail printTimeJobDetail(){
		return JobBuilder.newJob(MyJob1.class)
		.withIdentity("gupaoJob")
		.usingJobData("gupao", "职位更好的你")
		.storeDurably()
		.build();
	}
	@Bean
	public Trigger printTimeJobTrigger() {
		CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
		return TriggerBuilder.newTrigger()
		.forJob(printTimeJobDetail())
		.withIdentity("quartzTaskService")
		.withSchedule(cronScheduleBuilder)
		.build();
	}
}

5 动态调度的实现

springboot-quartz 工程
传统的 Spring 方式集成,由于任务信息全部配置在 xml 文件中,如果需要操作任务或者修改任务运行频率,只能重新编译、打包、部署、重启,如果有紧急问题需要处理,会浪费很多的时间。
有没有可以动态调度任务的方法?比如停止一个 Job?启动一个 Job?修改 Job 的触发频率?
读取配置文件、写入配置文件、重启 Scheduler 或重启应用明显是不可取的。
对于这种频繁变更并且需要实时生效的配置信息,我们可以放到哪里?
ZK、Redis、DB tables。
并且,我们可以提供一个界面,实现对数据表的轻松操作。

5.1 配置管理

这里我们用最简单的数据库的实现。
问题 1:建一张什么样的表?参考 JobDetail 的属性

CREATE TABLE `sys_job`(
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID', `job_name` varchar(512) NOT NULL COMMENT '任务名称', `job_group` varchar(512) NOT NULL COMMENT '任务组名', `job_cron` varchar(512) NOT NULL COMMENT '时间表达式', `job_class_path` varchar(1024) NOT NULL COMMENT '类路径,全类型', `job_data_map` varchar(1024) DEFAULT NULL COMMENT '传递 map 参数', `job_status` int(2) NOT NULL COMMENT '状态:1 启用 0 停用', `job_describe` varchar(1024) DEFAULT NULL COMMENT '任务功能描述', PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8;

5.2 数据操作与任务调度

操作数据表非常简单,SSM 增删改查。
但是在修改了表的数据之后,怎么让调度器知道呢?
调度器的接口:Scheduler
在我们的需求中,我们需要做的事情:
1、 新增一个任务
2、 删除一个任务
3、 启动、停止一个任务
4、 修改任务的信息(包括调度规律)

5.3 容器启动与 Service 注入

5.3.1 容器启动

因为任务没有定义在 ApplicationContext.xml 中,而是放到了数据库中,Spring Boot 启动时,怎么读取任务信息?
或者,怎么在 Spring 启动完成的时候做一些事情?
创建一个类,实现 CommandLineRunner 接口,实现 run 方法。
从表中查出状态是 1 的任务,然后构建。

5.3.2 Service 类注入到 Job 中

Spring Bean 如何注入到实现了 Job 接口的类中?
例如在 TestTask3 中,需要注入 ISysJobService,查询数据库发送邮件。
如果没有任何配置,注入会报空指针异常。
原因:
因为定时任务 Job 对象的实例化过程是在 Quartz 中进行的,而 Service Bean 是由Spring 容器管理的,Quartz 察觉不到 Service Bean 的存在,所以无法将 Service Bean装配到 Job 对象中。
分析:
Quartz 集成到 Spring 中,用到 SchedulerFactoryBean,其实现了 InitializingBean方法,在唯一的方法 afterPropertiesSet()在 Bean 的属性初始化后调用。调度器用 AdaptableJobFactory 对 Job 对象进行实例化。所以,如果我们可以把这个 JobFactory 指定为我们自定义的工厂的话,就可以在 Job 实例化完成之后,把 Job纳入到 Spring 容器中管理。
解决这个问题的步骤:
1、定义一个 AdaptableJobFactory,实现 JobFactory 接口,实现接口定义的newJob 方法,在这里面返回 Job 实例
在这里插入图片描述
2、定义一个 MyJobFactory,继承 AdaptableJobFactory。
使用 Spring 的 AutowireCapableBeanFactory,把 Job 实例注入到容器中。

@Component
public class MyJobFactory extends AdaptableJobFactory {
@Autowired
	private AutowireCapableBeanFactory capableBeanFactory;
		protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
		Object jobInstance = super.createJobInstance(bundle);
		capableBeanFactory.autowireBean(jobInstance);
		return jobInstance;
	}
}

3、指定 Scheduler 的 JobFactory 为自定义的 JobFactory。

scheduler.setJobFactory(myJobFactory);

6 Quartz 集群部署

springboot-quartz 工程

6.1 为什么需要集群?

1、防止单点故障,减少对业务的影响
2、减少节点的压力,例如在 10 点要触发 1000 个任务,如果有 10 个节点,则每个节点之需要执行 100 个任务

6.2 集群需要解决的问题?

1、任务重跑,因为节点部署的内容是一样的,到 10 点的时候,每个节点都会执行相同的操作,引起数据混乱。比如跑批,绝对不能执行多次。
2、任务漏跑,假如任务是平均分配的,本来应该在某个节点上执行的任务,因为节点故障,一直没有得到执行。
3、水平集群需要注意时间同步问题
4、Quartz 使用的是随机的负载均衡算法,不能指定节点执行
所以必须要有一种共享数据或者通信的机制。在分布式系统的不同节点中,我们可以采用什么样的方式,实现数据共享?
两两通信,或者基于分布式的服务,实现数据共享。
例如:ZK、Redis、DB。
在 Quartz 中,提供了一种简单的方式,基于数据库共享任务执行信息。也就是说,一个节点执行任务的时候,会操作数据库,其他的节点查询数据库,便可以感知到了。
同样的问题:建什么表?哪些字段?依旧使用系统自带的 11 张表

6.3 集群配置与验证

quartz.properties 配置。
四个配置:集群实例 ID、集群开关、数据库持久化、数据源信息
注意先清空 quartz 所有表、改端口、两个任务频率改成一样
验证 1:先后启动 2 个节点,任务是否重跑
验证 2:停掉一个节点,任务是否漏

7 Quartz 调度原理

问题:
1、Job 没有继承 Thread 和实现 Runnable,是怎么被调用的?通过反射还是什么?
2、任务是什么时候被调度的?是谁在监视任务还是监视 Trigger?
3、任务是怎么被调用的?谁执行了任务?
4、任务本身有状态吗?还是触发器有状态?
看源码的入口

Scheduler scheduler = factory.getScheduler();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();

7.1 获取调度器实例

7.1.1 读取配置文件
public Scheduler getScheduler() throws SchedulerException {
	if (cfg == null) {
		// 读取 quartz.properties 配置文件
		initialize();
	}
	// 这个类是一个 HashMap,用来基于调度器的名称保证调度器的唯一性
	SchedulerRepository schedRep = SchedulerRepository.getInstance();
	Scheduler sched = schedRep.lookup(getSchedulerName());
	// 如果调度器已经存在了
	if (sched != null) {
		// 调度器关闭了,移除
		if (sched.isShutdown()) {
			schedRep.remove(getSchedulerName());
		} else {
			// 返回调度器
			return sched;
		}
	}
	// 调度器不存在,初始化
	sched = instantiate();
	return sched;
}

instantiate()方法中做了初始化的所有工作:

// 存储任务信息的 JobStore
JobStore js = null;
// 创建线程池,默认是 SimpleThreadPool
ThreadPool tp = null;
// 创建调度器
QuartzScheduler qs = null;
// 连接数据库的连接管理器
DBConnectionManager dbMgr = null;
// 自动生成 ID
// 创建线程执行器,默认为 DefaultThreadExecutor
ThreadExecutor threadExecutor;

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

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

相关文章

机器学习模型可解释性的结果分析

模型的可解释性是机器学习领域的一个重要分支&#xff0c;随着 AI 应用范围的不断扩大&#xff0c;人们越来越不满足于模型的黑盒特性&#xff0c;与此同时&#xff0c;金融、自动驾驶等领域的法律法规也对模型的可解释性提出了更高的要求&#xff0c;在可解释 AI 一文中我们已…

MySQL复习汇总(图书管理系统)

MySQL图书管理系统&#xff08;49-94&#xff09;源码_71.备份book数据库到e盘的mybook.sql文件(备份文件中要求包含建库命令)-CSDN博客 -- 1、 创建一个名称为book的数据库。 -- 2、 打开book数据库 -- 3、 创建数据表分别如下&#xff08;除外键之外&#xff09;…

2.1.1 预期年化收益率

跳转到根目录&#xff1a;知行合一&#xff1a;投资篇 已完成&#xff1a; 1、投资&技术   1.1.1 投资-编程基础-numpy   1.1.2 投资-编程基础-pandas   1.2 金融数据处理   1.3 金融数据可视化 2、投资方法论   2.1.1 预期年化收益率 3、投资实证   [3.1 202…

GPT实战系列-简单聊聊LangChain

GPT实战系列-简单聊聊LangChain LLM大模型相关文章&#xff1a; GPT实战系列-ChatGLM3本地部署CUDA111080Ti显卡24G实战方案 GPT实战系列-Baichuan2本地化部署实战方案 GPT实战系列-大话LLM大模型训练 GPT实战系列-探究GPT等大模型的文本生成 GPT实战系列-Baichuan2等大模…

元数据管理平台对比预研 Atlas VS Datahub VS Openmetadata

大家好&#xff0c;我是独孤风。元数据管理平台层出不穷&#xff0c;但目前主流的还是Atlas、Datahub、Openmetadata三家&#xff0c;那么我们该如何选择呢&#xff1f; 本文就带大家对比一下,这三个平台优势劣势。要了解元数据管理平台&#xff0c;先要从架构说起。 正文共&am…

【算法Hot100系列】合并 K 个升序链表

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…

[AutoSar]基础部分 RTE 06 对runnable的触发和SWC的影响

目录 关键词平台说明一、runnable二、RTE的event2.1Mode类型event2.2周期触发类型2.3 数据交互触发 三、internal runnable value四、专属运行区指定五、per_instance memory 关键词 嵌入式、C语言、autosar、Rte 平台说明 项目ValueOSautosar OSautosar厂商vector芯片厂商T…

NGINX 配置本地HTTPS(免费证书)

生成秘钥key,运行: $ openssl genrsa -des3 -out server.key 2048 会有两次要求输入密码,输入同一个即可。输入密码然后你就获得了一个server.key文件。 以后使用此文件(通过openssl提供的命令或API)可能经常回要求输入密码,如果想去除输入密码的步骤可以使用以下命令: $ op…

揭秘六大热门认证考试

六大热门认证考试是什么❓今天为大家详细解读PMP、ACP、CDGA、软考中项、软考高项、NPDP、CISP等热门认证考试&#xff0c;让你不再彷徨&#x1f447; 1️⃣PMP &#x1f451;PMP认证是全qiu公ren的项目管理专业认证&#xff0c;旨在评估项目管理人员在项目过程中所需的知识、技…

基于JAVA的中小学教师课程排课系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 角色管理模块2.2 课程档案模块2.3 排课位置模块2.4 排课申请模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 角色表3.2.2 课程表3.2.3 排课位置表3.2.4 排课申请表 四、系统展示五、核心代码5.1 查询课程5.2 新增课…

C++/OpenGL应用程序

图像应用程序大部分是 C 编写&#xff0c;OpenGL 调用实现与 3D 渲染相关任务将会使用一些扩展库: GLEW、GLM、GLFW、SOLL2 等。 GLFW 库包含 GLFWwindow 类&#xff0c;我们可以在其上进行 3D 场景绘制。OpenGL 也向我们提供了用于 GLSL 程序载入可编程着色阶段并对其进行编译…

【idea】解决sprintboot项目创建遇到的问题2

本篇是继【idea】解决sprintboot项目创建遇到的问题_java.lang.illegalargumentexception: unable to inst-CSDN博客 目录 一、Dependency com.mysql:mysql-connector-j: not found 二、Could not find artifact org.springframework.boot:spring-boot-maven-plugin:pom:4.0…

Android RecyleView 使用 Gilde 加载图片引发的卡顿问题

Glide 是一个用于 Android 的图片加载和缓存库。它可以帮助开发者快速、高效地加载网络图片、本地文件和视频帧&#xff0c;并且能够自动缓存图片数据&#xff0c;减少网络请求。Glide 具有良好的性能和易用的 API&#xff0c;支持常见的图片加载需求&#xff0c;例如图片压缩、…

springboot 房屋租赁系统

spring boot mysql mybatis 前台后端

JavaWeb——后端之maven

三、后端Web开发 1. Maven 1.1 概念 概念&#xff1a; 一款用于管理和构建java项目的工具&#xff0c;是apache下的一个开源项目 作用&#xff1a; 依赖管理&#xff1a;jar包&#xff0c;避免版本冲突问题——不用手动导jar包&#xff0c;只需要在配置文件&#xff08;pom…

项目管理工具Maven

Maven Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. Maven基础内容 2. Maven的依赖管…

使用jasypt进行配置文件加密

1、导入依赖 <dependency> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-spring-boot-starter</artifactId> <version>3.0.2</version> </dependency> 可能出现的问题 &#xff1a; 依赖不要从pdf中直…

Unity 0GC或者最大限度降低GC方案

文章目录 GC带来的问题性能瓶颈玩家体验受损 优化关键点1. **对象池技术**&#xff1a;2. **内存管理优化**&#xff1a;3. **UGUI优化**&#xff1a;4. **ECS架构下的优化**&#xff1a;5. **资源管理**&#xff1a;6. **自定义数据结构与算法**&#xff1a;7. **开启增量GC&a…

分布式事务理论及Seata实践

分布式事务简介 事务是指作为单个逻辑工作单元执行的一系列操作&#xff0c;要么完全地执行&#xff0c;要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成&#xff0c;否则不会永久更新面向数据的资源。事务的四个特征&#xff08;ACID&#xff09; …

算法第十三天-组合总和Ⅱ

组合总和Ⅱ 题目要求 解题思路 按顺序搜索&#xff0c;设置合理的变量&#xff0c;在搜索的过程中判断是否会出现重复集结果。重点理解对输入数组排序的作用和参考代码中 大剪枝和小剪枝 的意思 这道题域上一问的区别在于&#xff1a; 第39题&#xff1a;candidates中的数字…