Quartz.NET 架构与源代码分析系列 part 1 :Quartz.NET 入门

本文介绍了作业调度的概念及其在Windows XP系统中的实现——任务计划。重点解析了Quartz.NET,一个强大的开源作业调度框架,涵盖了其特点、安装配置过程及基本使用方法。

概述

作业调度的目标在于按照预先确定的时间和指定的顺序来确保高效的数据处理流程,从而最大限度的使用系统资源。批处理流程是一种在无需最终用户干预的方式下在后台通过顺序方式运行的操作。

Windows XP系统也自带了“任务计划”,它是一个简单任务调度应用,可以在“开始”->“所有程序”->“附件”->“系统工具”->“任务计划”里找到。如图1;

image

图1.Windows 的任务计划

Quartz.NET 是一个开源的作业调度框架,它可以被在小型应用程序甚至是企业级的应用程序。它有如下几个特点:

  • API 操作简单,只要几行简单的代码你就可以在应用程序里面实现自己的作业调度,并实时监视作业执行情况
  • 触发器功能强大,比 Windows 的任务计划提供更细的触发粒度,你可以使用“Cron表达式(后文将介绍)”来实现如:每周星期一到星期五 8:00am,5:00pm(工作时间) 执行某一件任务
  • 良好的可扩展性,它基于接口编程,你可以实现自己的 Schedule 调度器,Job 作业,以及 Trigger 触发器等
  • 作业可以保存在 RAM 中,也可以持久化到数据库,支持多种数据库类型:SqlServer、Oracle、MySql等
  • 集群,这是一个高级应用,可以在多台计算机之间创建负载平衡、容错处理

使用

最新的版本是1.0 正式版,有 Quartz.2008.sln 和 Quartz.Server.2008.sln(分步式应用,将在下面的系列分析) ,用 Visual Studio 2008 打开 Quartz.2008.sln ,方案如图2 所示:

image

图2. Quartz.NET解决方案

Quartz.NET是核心的 Quartz 库,它的文件组织结构及作用如图3所示:

image

图3.Quartz.NET文件组织结构

Quartz.NET 的文件组织结构并不遵循一定的规范,比如“SPI” 文件夹存放调度器、作业、线程池接口,最外层也放了很多接口,如图3所示。但是大部分都可以直接辨别出来,所以这不会对我们阅读代码造成很大的影响。

下面是一个 Quartz.NET 的简单例子:

ContractedBlock.gif ExpandedBlockStart.gif Code
None.gif//初始化调度器工厂 
None.gif
ISchedulerFactory sf = new StdSchedulerFactory(); 
None.gif
//获取默认调度器 
None.gif
IScheduler scheduler = sf.GetScheduler(); 
None.gif
None.gif
//作业 
None.gif
JobDetail job = new JobDetail("计算作业""组1"typeof(Job1)); 
None.gif
None.gif
//触发器 
None.gif
SimpleTrigger trigger = new SimpleTrigger("触发器1""触发器组1"5new TimeSpan(005)); 
None.gif
None.gif
//关联任务和触发器 
None.gif
scheduler.ScheduleJob(job, trigger); 
None.gif
//开始任务 
None.gif
scheduler.Start();
None.gif

首先,我们初始化一个标准的调度器工厂 StdSchedulerFactory ,并用 GetScheduler() 方法创建一个调度器。下一步是声明一个作业对象 JobDetail,它有3 个参数:作业名称、作业组名称、作业的类型。接着,实例化一个 SimpleTrigger 触发器对象,SimpleTrigger 类有6 个构造函数,上面例子的 4 个参数分别为:触发器名称、触发器组名称、循环执行次数、执行间隔。调度器调用 ScheduleJob 方法把作业对象和触发器关联起来,打开触发器就可以开始作业了。

要执行的作业 Job1 是实现了 IJob 接口的类,IJob 接口只有一个简单的方法:

ContractedBlock.gif ExpandedBlockStart.gif Code
void Execute(JobExecutionContext context)

每一个要执行的作业都要继承 IJob 接口并实现 Execute 方法。

下面是Job1 的定义:

ContractedBlock.gif ExpandedBlockStart.gif Code
None.gifpublic class Job1 :IJob 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
InBlock.gif     
private int i = 0
InBlock.gif     
public void Execute(JobExecutionContext context) 
ExpandedSubBlockStart.gifContractedSubBlock.gif     
dot.gif
InBlock.gif        Console.WriteLine(
++i); 
ExpandedSubBlockEnd.gif     }
 
ExpandedBlockEnd.gif}

上面代码的执行结果是连续输出6 个1(重复执行5次,加上第一次执行,一共6 次)。

下一篇我将要介绍 Job 作业。

思想,原理,技术,应用

参考文章

1.Microsoft 管理解决方案:作业调度

2.Quartz.NET

 

目录:Quartz.NET 架构与源代码分析系列
下一篇:Quartz.NET 架构与源代码分析系列 part 2 :Job 作业

转载于:https://www.cnblogs.com/Doho/archive/2009/03/11/1408886.html

eco.gateway.enablePcWebApiAppCode=true eco.gateway.pcWebApiAppCode=alipay.planet.xxxapp The configuration you provided appears to be related to enabling and setting up a specific application code for a gateway service, likely in a backend or microservices architecture. Here's a breakdown of what each line might mean: Configuration Breakdown: eco.gateway.enablePcWebApiAppCode=true Purpose: This setting likely enables the use of an application-specific API code for the "PC Web" gateway. Implication: When set to true, the gateway will allow or process requests associated with the pcWebApiAppCode. If set to false, this feature would be disabled. eco.gateway.pcWebApiAppCode=alipay.planet.xxxapp Purpose: This specifies the application code (alipay.planet.xxxapp) that the gateway should recognize when handling PC Web API requests. Implication: The gateway will use this code to identify, route, or authenticate requests related to the "PC Web" platform. The placeholder xxxapp suggests this is a placeholder and should be replaced with the actual application identifier. Possible Use Case: Gateway Service: This configuration seems to belong to a gateway service that handles API requests for different platforms (e.g., PC Web, Mobile). Application Code: The pcWebApiAppCode is likely used to distinguish between different applications or modules accessing the gateway. For example, an "Alipay" app might have a specific code to identify its requests. Enable/Disable: The enablePcWebApiAppCode flag allows toggling this feature, which could be useful for testing or security purposes. Common Questions: What happens if enablePcWebApiAppCode is set to false? The gateway might reject or ignore requests with the pcWebApiAppCode, depending on how the service is implemented. Is alipay.planet.xxxapp a valid application code? The xxxapp part seems like a placeholder. It should be replaced with a valid, unique identifier for the application (e.g., alipay.planet.myapp). Where is this configuration used? This is typically part of a backend configuration file (e.g., application.properties, application.yml, or environment variables). It would be read by the gateway service at runtime. What other related configurations might exist? Similar settings for other platforms (e.g., Mobile Web, iOS, Android) might exist, such as eco.gateway.enableMobileWebApiAppCode or eco.gateway.mobileWebApiAppCode. Security Considerations: Ensure that the pcWebApiAppCode is kept confidential if it is sensitive (e.g., used for authentication or authorization). Verify that enabling this feature does not inadvertently expose the gateway to unauthorized requests. If you need further clarification or help with implementing this configuration, feel free to provide more context! 第二行这个是什么 第二行配置: eco.gateway.pcWebApiAppCode=alipay.planet.xxxapp 解释: eco.gateway.pcWebApiAppCode 这是一个配置键(Key),用于定义某个特定的应用代码(Application Code)。 eco.gateway 可能是一个命名空间(Namespace),用于网关(Gateway)相关的配置。 pcWebApiAppCode 表示这个配置项是用于 "PC Web API" 的应用代码。 alipay.planet.xxxapp 这是配置的值(Value),表示一个具体的应用代码(App Code)。 在这个例子中,alipay.planet.xxxapp 可能是一个占位符(Placeholder),表示某个具体的应用标识。 实际使用时,通常需要替换为真实的应用程序标识符(例如 alipay.planet.myapplication)。 作用: 这个配置项可能是用于标识某个特定的应用程序或服务,当网关处理 "PC Web API" 请求时,会根据这个应用代码进行相应的处理(例如路由、鉴权等)。 示例场景: 假设这是一个支付网关服务,alipay.planet.xxxapp 可能是某个支付宝支付应用的应用代码。网关会根据这个代码识别请求的来源,并进行相应的处理。 如果你有更多上下文或具体问题,可以进一步说明! # ------------ PcWebApi ------------- eco.gateway.enablePcWebApiAppCode=true eco.gateway.pcWebApiAppCode=alipay.planet.${spring.application.name} 这段配置是关于一个名为 PcWebApi 的功能模块,具体说明如下: 配置项解析 1. eco.gateway.enablePcWebApiAppCode=true 含义:启用 PcWebApi 相关的应用代码(App Code)功能。 作用:当设置为 true 时,网关会开启对 PcWebApiAppCode 的处理逻辑(例如验证、路由等)。如果设置为 false,则禁用该功能。 2. eco.gateway.pcWebApiAppCode=alipay.planet.${spring.application.name} 含义: 这是一个动态配置项,${spring.application.name} 是 Spring Boot 的内置变量,表示当前应用的名称(在 application.properties 或环境变量中定义)。 配置值的最终结果是 alipay.planet.<当前应用名>。例如: 如果 spring.application.name=my-app,则 eco.gateway.pcWebApiAppCode 的值为 alipay.planet.my-app。 如果 spring.application.name=payment-service,则值为 alipay.planet.payment-service。 作用:为每个应用生成唯一的应用代码(App Code),便于网关根据代码识别请求来源。 可能的使用场景 应用标识: 网关通过 pcWebApiAppCode 来标识不同应用的请求,确保请求被正确路由或处理。 例如:不同业务模块(如支付、订单、会员)的应用会使用不同的 spring.application.name, @RequestMapping(value = "/test/CertificateListQueryReq", method = RequestMethod.POST)如果我想访问这个,我需要如何拼接url 要访问这个接口,你需要按照以下步骤拼接 URL: 1. 基础 URL 首先,你需要知道你的服务的基础 URL(通常是服务的域名或 IP 地址,例如 http://localhost:8080 或 https://api.example.com)。 2. 接口路径 根据你的代码,接口的路径是: /test/CertificateListQueryReq 3. 完整的 URL 将基础 URL 和接口路径拼接起来。例如: 如果是本地服务(端口 8080): http://localhost:8080/test/CertificateListQueryReq 如果是生产环境(假设域名是 https://api.example.com): https://api.example.com/test/CertificateListQueryReq 4. HTTP 方法 这个接口使用的是 POST 方法,所以你需要使用 POST 请求来访问它。 示例请求 使用 curl 发送请求: bash curl -X POST \ http://localhost:8080/test/CertificateListQueryReq \ -H "Content-Type: application/json" \ -d '{"key":"value"}' 使用 Postman: 选择 POST 方法。 输入 URL(例如 http://localhost:8080/test/CertificateListQueryReq)。 在 Body 部分输入 JSON 数据(如果接口需要参数)。 设置 Content-Type 为 application/json。 注意事项 如果你的服务部署在某个上下文路径(context path)下(例如 /myapp),需要在 URL 中加上。例如: http://localhost:8080/myapp/test/CertificateListQueryReq 确保接口的权限和认证配置正确,否则可能会返回 403 或 401 错误。 如果你的服务使用了 HTTPS,记得使用 https:// 而不是 http://。 如果你还有其他问题(例如如何测试、如何传递参数等),可以继续提问! quarzt如何从持久化的数据库中读取需要执行的任务吗,来个代码实例 在使用 Quartz 调度器时,可以通过持久化存储(如数据库)来管理任务的调度。以下是一个示例代码,展示如何从数据库中读取任务并启动 Quartz 调度器。 1. 配置 Quartz 数据源 首先,需要在 quartz.properties 文件中配置 Quartz 使用数据库存储: properties # quartz.properties org.quartz.scheduler.instanceName = MyScheduler org.quartz.scheduler.instanceId = AUTO org.quartz.threadPool.threadCount = 3 org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.useProperties = false org.quartz.jobStore.dataSource = myDS org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.isClustered = true org.quartz.dataSource.myDS.driver = com.mysql.cj.jdbc.Driver org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz org.quartz.dataSource.myDS.user = root org.quartz.dataSource.myDS.password = password org.quartz.dataSource.myDS.maxConnections = 5 2. 创建 Quartz 数据库Quartz 提供了一些 SQL 脚本来创建所需的表(在 quartz 数据库中运行这些脚本)。以下是 MySQL 的例子: sql -- 创建 Quartz 数据表的 SQL 脚本 CREATE TABLE QRTZ_JOB_DETAILS ( SCHED_NAME VARCHAR(120) NOT NULL, JOB_NAME VARCHAR(200) NOT NULL, JOB_GROUP VARCHAR(200) NOT NULL, DESCRIPTION VARCHAR(250) NULL, JOB_CLASS_NAME VARCHAR(250) NOT NULL, IS_DURABLE VARCHAR(1) NOT NULL, IS_NONCONCURRENT VARCHAR(1) NOT NULL, IS_UPDATE_DATA VARCHAR(1) NOT NULL, REQUESTS_RECOVERY VARCHAR(1) NOT NULL, JOB_DATA BLOB NULL, PRIMARY KEY (SCHED_NAME, JOB_NAME, JOB_GROUP) ); CREATE TABLE QRTZ_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, JOB_NAME VARCHAR(200) NOT NULL, JOB_GROUP VARCHAR(200) NOT NULL, DESCRIPTION VARCHAR(250) NULL, NEXT_FIRE_TIME BIGINT NULL, PREV_FIRE_TIME BIGINT NULL, PRIORITY INTEGER NULL, TRIGGER_STATE VARCHAR(16) NOT NULL, TRIGGER_TYPE VARCHAR(8) NOT NULL, START_TIME BIGINT NOT NULL, END_TIME BIGINT NULL, CALENDAR_NAME VARCHAR(200) NULL, MISFIRE_INSTR SMALLINT NULL, JOB_DATA BLOB NULL, PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME, JOB_NAME, JOB_GROUP) REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME, JOB_NAME, JOB_GROUP) ); -- 其他表可以参考 Quartz 官方文档 3. Java 代码示例 以下是一个完整的示例代码,展示如何从数据库中读取任务并启动 Quartz 调度器: 3.1 创建一个简单的任务类 java import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; public class HelloJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("Hello, Quartz! 时间: " + new java.util.Date()); } } 3.2 创建一个 Quartz 调度器并启动任务 java import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; public class QuartzExample { public static void main(String[] args) { try { // 1. 创建 Scheduler Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); // 2. 启动 Scheduler scheduler.start(); // 3. 定义一个 JobDetail JobDetail job = JobBuilder.newJob(HelloJob.class) .withIdentity("job1", "group1") .build(); // 4. 定义一个 Trigger Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(5) .repeatForever()) .build(); // 5. 将 Job 和 Trigger 注册到 Scheduler scheduler.scheduleJob(job, trigger); // 6. Scheduler 会根据配置的表存储任务 System.out.println("Scheduler 已启动..."); } catch (SchedulerException e) { e.printStackTrace(); } } } 3.3 从数据库中读取任务 当 Quartz 调度器启动时,它会自动从 QRTZ_JOB_DETAILS 和 QRTZ_TRIGGERS 表中读取任务和触发器的定义,并开始执行。如果你在数据库中手动插入了任务,Quartz 会自动加载它们。 4. 数据库中的任务示例 假设你在数据库中插入了以下任务: sql INSERT INTO QRTZ_JOB_DETAILS (SCHED_NAME, JOB_NAME, JOB_GROUP, JOB_CLASS_NAME, IS_DURABLE, IS_NONCONCURRENT, IS_UPDATE_DATA, REQUESTS_RECOVERY, JOB_DATA) VALUES ('MyScheduler', 'job1', 'group1', 'com.example.HelloJob', 'Y', 'N', 'N', 'N', NULL); INSERT INTO QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, JOB_NAME, JOB_GROUP, START_TIME, NEXT_FIRE_TIME, TRIGGER_STATE, TRIGGER_TYPE, REPEAT_INTERVAL, REPEAT_COUNT) VALUES ('MyScheduler', 'trigger1', 'group1', 'job1', 'group1', 1697040000000, 1697040005000, 'WAITING', 'SIMPLE', 5000, -1); 当 Quartz 调度器启动时,它会自动加载这些任务并开始执行。 总结 配置 Quartz 使用数据库存储(通过 quartz.properties)。 创建 Quartz 数据表。 使用 Java 代码定义任务并启动调度器。 Quartz 会自动从数据库中读取任务和触发器的定义。 希望这个示例对你有帮助!如果有任何问题,请随时提问。 我的问题是,如果我将一些任务信息保存到数据库quartz如何从数据库中读取这些配置,然后去依次执行这些任务
最新发布
09-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值