您的位置:首页 > 健康 > 美食 > 产品设计网址_app开发制作系统哪个好_查域名备案_西安网站关键词推广

产品设计网址_app开发制作系统哪个好_查域名备案_西安网站关键词推广

2025/1/8 5:42:37 来源:https://blog.csdn.net/GJ_863/article/details/144172681  浏览:    关键词:产品设计网址_app开发制作系统哪个好_查域名备案_西安网站关键词推广
产品设计网址_app开发制作系统哪个好_查域名备案_西安网站关键词推广

Quartz

之前在项目中用定时任务都是直接用的Spring的@Scheduled注解,因为遇到的业务都比较简单,比如定时更新榜单,支付功能中的定时查单,最近在写一个课堂助手的项目,要实现定时任务的业务对任务有增删改查的需求,@Scheduled已经无法满足了,so,我选择了Quartz

Quartz是OpenSymphony开源的一个项目,是一个由Java编写的开源作业调度框架。

  1. 支持分布式高可用
  2. 支持持久化,支持调度数据的多种存储方式
  3. 支持多任务调度和管理

存储方式

  • RAMJobStore
    • 不要外部数据库,配置容易,运行快
    • 调度程序信息存在内存中,当应用程序停止运行时,所有调度信息将丢失
    • 而且因为存在内存中,Job和Trigger的数量将会受到限制
  • JDBCJobStore
    • 支持集群
    • 所有任务信息都会保存在数据库中,不会因为程序停止运行丢失
    • 运行速度取决于数据库的速度

组件

Quartz的组成

在这里插入图片描述

JobDetail

Job相当于是线程池中的task,是定时任务真正业务逻辑的部分,Job需要封装成JobDetail,一个Job可以对应多JobDetail

通过JobBuilder创建

Trigger

触发器,定义触发时间,常用的有以下两种

  • SimleTrigger:用于实现简单的定时,比如定频率的执行某个任务
  • CronTrigger:配合Cron表达式使用,可以实现相对复杂的业务,比如到某个具体日期执行,每个月几号执行等

通过TriggerBuilder创建

Scheduler

调度器,帮我们把JobDetail和Trigger绑定在一起,按照Trigger中定义的触发时间去触发JobDetail中的Job

使用SchedulerFactory创建

  • DirectSchedulerFactory:需要在代码中定义一些属性,不常用
  • StdSchedulerFactory:从配置文件中获取配置,推荐使用
//调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); // 这里简单获取了一个默认的,可以在配置文件中配置属性并获取
scheduler.scheduleJob(jobDetail,trigger);
scheduler.start();

任务每次执行Scheduler都会根据JobDetail创建一个新的Job实例,让任务并发执行,如果我们不想要这种特性,想要前一个任务执行完了才会执行下一个,可以使用@DisallowConcurrentExecution注解关闭

由于Scheduler每次执行都会根据JobDetail创建一个新的Job实例,jobDataMap属于JobDetail,那么每次也是一个新的,我们可以使用@PersistJobDataAfterExecution来让JobDataMap持久化

JobDataMap

我们可以看到JobDetail和Trigger中都有JobDataMap,jobDataMap可以用于在启动这个定时器时,往任务中传递一些参数

任务类获取参数的方式有两种

  • 通过获取jobDataMap再获取对应键值
  • 在任务类中定义相关字段,设置好set方法,框架会自动往里面设置值,如果JobDetail和Trigger里设置相同名称的话,JobDetail的会被覆盖掉
JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity("job1","group1").usingJobData("job","gwj's job") // 用来设置JobDetail中的JobDataMap中的值.usingJobData("name","jobdetail").usingJobData("tong","jobde").build();Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1","triggerGroup1").usingJobData("trigger","my trigger")  // 用来设置Trigger中的JobDataMap中的值.usingJobData("name","trigger").usingJobData("tong","triggde").startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever()).build();

任务类

@Data
public class MyJob implements Job {private String name;@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {JobDataMap jobDetailMap = jobExecutionContext.getJobDetail().getJobDataMap(); // 获取JobDetail的JobDataMapJobDataMap triggerMap = jobExecutionContext.getTrigger().getJobDataMap(); // 获取Trigger的JobDataMapJobDataMap mergeMap = jobExecutionContext.getMergedJobDataMap();  // 获取混合JobDataMapSystem.out.println(mergeMap.get("job"));  // gwj's jobSystem.out.println(mergeMap.get("trigger")); // my triggerSystem.out.println(mergeMap.get("tong"));  // triggdeSystem.out.println(name); // trigger// 具体任务流程……}
}

整合SpringBoot

导入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

配置文件

spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/test_dbusername: rootpassword: 111111type: com.alibaba.druid.pool.DruidDataSourceservlet:multipart:max-file-size: 2048MBmax-request-size: 2048MB# 定时任务配置quartz:# 数据库方式job-store-type: jdbcjdbc:initialize-schema: always # 数据库架构初始化模式# never:从不 always:每次都清空数据库初始化 embedded:只初始化内存数据库(默认)# quartz 相关属性配置properties:org:quartz:scheduler:instanceName: demoSchedulerinstanceId: AUTOjobStore:class: org.springframework.scheduling.quartz.LocalDataSourceJobStoredriverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegatetablePrefix: QRTZ_isClustered: trueclusterCheckinInterval: 10000useProperties: falsethreadPool:class: org.quartz.simpl.SimpleThreadPoolthreadCount: 10threadPriority: 5threadsInheritContextClassLoaderOfInitializingThread: true

创建表

Quartz支持对任务进行crud,可以使用mysql存储记录我们的任务

方式一

配置文件中配置initialize-schema: always,项目启动后我们就可以看到数据库中自动生成了11张表,后面再删掉或者改成never就行

方式二

可以在Quartz的jar包中找到对应数据库的SQL脚本,拷贝出来执行即可

在这里插入图片描述在这里插入图片描述

表说明

表名说明
qrtz_blob_triggers以Blob 类型存储的触发器
qrtz calendars存放日历信息,quartz可配置一个日历来指定一个时间范围
qrtz_cron triggers存放cron类型的触发器
qrtz fired triggers存放已触发的触发器
qrtz job _details存放一个jobDetail信息
qrtz job listenersjob监听器
qrtz_locks存储程序的悲观锁的信息(假如使用了悲观锁)
qrtz_paused trigger_graps存放暂停掉的触发器
qrtz scheduler state调度器状态
qrtz simple triggers简单触发器的信息
qrtz_trigger_listeners触发器监听器

编写业务类

示例

/*** 任务业务类,用于动态处理任务信息* @author gwj* @date 2024/11/29 下午2:17*/
public interface JobService {/*** 任务数据*/String TASK_DATA = "taskData";/*** 添加定时任务* @param jobClass* @param jobName* @param cron* @param data*/void addCronJob(Class jobClass, String jobName, String cron, String data);/*** 添加立即执行的任务* @param jobClass* @param jobName* @param data*/void addCronJob(Class jobClass, String jobName, String data);/*** 暂停任务* @param jobName* @param jobGroup*/void pauseJob(String jobName, String jobGroup);/*** 恢复任务* @param triggerName* @param triggerGroup*/void resumeJob(String triggerName, String triggerGroup);/*** 删除job* @param jobName* @param jobGroup*/void deleteJob(String jobName, String jobGroup);
}
/*** @author gwj*/
@Slf4j
@Service
public class JobServiceImpl implements JobService {/*** Quartz定时任务核心的功能实现类*/@Autowiredprivate Scheduler scheduler;@Overridepublic void addCronJob(Class jobClass, String jobName, String cron, String data) {String jobGroup = JobGroup.SYSTEM;// 自动命名if(StringUtils.isEmpty(jobName)){jobName = jobClass.getSimpleName().toUpperCase() + "_"+ IdWorker.getIdStr();}try {JobKey jobKey = JobKey.jobKey(jobName, jobGroup);JobDetail jobDetail = scheduler.getJobDetail(jobKey);if (jobDetail != null) {log.info("++++++++++任务:{} 已存在", jobName);this.deleteJob(jobName, jobGroup);}log.info("++++++++++构建任务:{},{},{},{},{} ", jobClass.toString(), jobName, jobGroup, cron, data);//构建job信息jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroup).build();//用JopDataMap来传递数据jobDetail.getJobDataMap().put(TASK_DATA, data);//按新的cronExpression表达式构建一个新的triggerTrigger trigger = null;// 有表达式的按表达式if(!StringUtils.isEmpty(cron)){log.info("+++++表达式执行:"+ JSON.toJSONString(jobDetail));//表达式调度构建器CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).withSchedule(scheduleBuilder).build();}else{// 无表达式则立即执行log.info("+++++立即执行:"+ JSON.toJSONString(jobDetail));trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).startNow().build();}scheduler.scheduleJob(jobDetail, trigger);} catch (Exception e) {e.printStackTrace();}}@Overridepublic void addCronJob(Class jobClass, String jobName, String data) {// 立即执行任务this.addCronJob(jobClass, jobName, null, data);}@Overridepublic void pauseJob(String jobName, String jobGroup) {try {TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);scheduler.pauseTrigger(triggerKey);log.info("++++++++++暂停任务:{}", jobName);} catch (SchedulerException e) {e.printStackTrace();}}@Overridepublic void resumeJob(String jobName, String jobGroup) {try {TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);scheduler.resumeTrigger(triggerKey);log.info("++++++++++重启任务:{}", jobName);} catch (SchedulerException e) {e.printStackTrace();}}@Overridepublic void deleteJob(String jobName, String jobGroup) {try {JobKey jobKey = JobKey.jobKey(jobName,jobGroup);scheduler.deleteJob(jobKey);log.info("++++++++++删除任务:{}", jobKey);} catch (SchedulerException e) {e.printStackTrace();}}
}

测试

/*** @author gwj* @date 2024/11/30 21:18*/
@RestController
@RequestMapping("/test")
public class TestController {@Resourceprivate JobService jobService;/*** 创建一个一分钟后执行的定时任务** @param id* @return*/@PostMappingpublic String addTask(Long id) {String jobName = JobPrefix.BREAK_EXAM + id;Date date = new Date();long l = date.getTime() + 1000 * 60;Date until = new Date(l);jobService.addCronJob(BreakExamJob.class,jobName, CronUtils.dateToCron(until),id+"");return "定时任务创建成功";}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com