资阳市网站seo,杭州软件定制开发app,iis7创建网站,网站制作自助目录
一 项目参考
二 个人的定时任务实现
1 基本搭建
1.创建一个spring项目
2.pom文件引入必要依赖
2 业务基本实现
2.1 主定时任务
2.2 业务类定时任务
3 Quartz
3.1 任务Job、JobDetail、JobBuilder
3.2 触发器 Trigger、TriggerBuilder
3.3 调度器Scheduler、Sc…
目录
一 项目参考
二 个人的定时任务实现
1 基本搭建
1.创建一个spring项目
2.pom文件引入必要依赖
2 业务基本实现
2.1 主定时任务
2.2 业务类定时任务
3 Quartz
3.1 任务Job、JobDetail、JobBuilder
3.2 触发器 Trigger、TriggerBuilder
3.3 调度器Scheduler、SchedulerFactory、SchedulerFactoryBean 公司旧系统需要增加定时任务功能甲方希望功能简洁且不增加运维人员工作量因此参考网上案例基于Spring矿机用Quartz写了简单的定时任务模块。
一 项目参考
Spring 集成quartz框架的两种方式_皮卡车厘子的博客-CSDN博客_spring集成quartz
Quartz- Quartz API以及Jobs 和Triggers介绍_小小工匠的博客-CSDN博客_quartz-jobs
定时任务框架Quartz-(一)Quartz入门与Demo搭建_是Guava不是瓜娃的博客-CSDN博客_quartz
Quartz-scheduler 定时器概述、核心 API 与 快速入门_蚩尤后裔的博客-CSDN博客_org.quartz-scheduler
项目使用的是quartz版本是2.2.1需要提前引入到pom文件中 !--核心包--dependencygroupIdorg.quartz-scheduler/groupIdartifactIdquartz/artifactIdversion2.2.1/version/dependency!--工具包--dependencygroupIdorg.quartz-scheduler/groupIdartifactIdquartz-jobs/artifactIdversion2.2.1/version/dependency
避免和谐这里复制一份留着自己看下面内容基本都是贴的链接里的因为这部分公司项目代码也是借鉴的模板所以贴了部分不涉密的模板代码块。 Java项目中常使用的定时器有JDK Timer、Quartz、Spring Task等三种。Quartz的功能强大配置也比较复杂适合大型、多定时任务的项目使用。Spring Task配置较为简单轻量需要Spring框架支持。JDK自带的定时器Timer使用灵活配置简单适合中小型项目。这里记录下quartz方式
一、Quartz作业类的继承方式来讲可以分为两类
1.作业类需要继承自特定的作业类基类如Quartz中需要继承自org.springframework.scheduling.quartz.QuartzJobBean 2.作业类即普通的java类不需要继承自任何基类。 使用QuartzJobBean需要继承而且在注入Spring容器中其他service时候需要在schedulerContextAsMap中注入比较麻烦否则不能成功(具体操作参考https://blog.csdn.net/whaosy/article/details/6298686)。
使用MethodInvokeJobDetailFactoryBean则需要指定targetObject任务实例和targetMethod实例中要执行的方法可以方便注入Spring容器中其他的service。后者优点是无侵入业务逻辑简单。所以我更推荐的第二种
二、从任务调度的触发时机来分这里主要是针对作业使用的触发器主要有以下两种
每隔指定时间则触发一次在Quartz中对应的触发器为org.springframework.scheduling.quartz.SimpleTriggerBean 每到指定时间则触发一次在Quartz中对应的调度器为org.springframework.scheduling.quartz.CronTriggerBean 三、下面只保留了原作者写的第二种——作业类不继承特定基类
package com.summer.job;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import com.summer.opendoor.service.OpenDoorService;Component
public class JobMethodInvoke{public JobMethodInvoke() {super();System.out.println(JobMethodInvoke初始化);}Autowiredprivate OpenDoorService openDoorService;protected void doSomething() {System.out.println(JOB任务执行了);openDoorService.open();}}
注意中间的引用关系如下图 ?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:contexthttp://www.springframework.org/schema/context xmlns:phttp://www.springframework.org/schema/pxmlns:aophttp://www.springframework.org/schema/aop xmlns:txhttp://www.springframework.org/schema/txxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd!--第一步 要执行任务的作业类。 --bean idtestQuartz classcom.summer.job.JobMethodInvoke /!-- 第二步 将需要执行的定时任务注入JOB中。 --bean idjobDetailclassorg.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBeanproperty nametargetObject reftestQuartz/property!-- 任务类中需要执行的方法 --property nametargetMethod valuedoSomething/property!-- 上一次未执行完成的要等待有再执行。 --property nameconcurrent valuefalse/property/bean!--第三步 基本的定时器会绑定具体的任务。 -- !-- 第一种 SimpleTriggerBean只支持按照一定频度调用任务如每隔30分钟运行一次。配置方式如下 --!-- bean idtestTriggerclassorg.springframework.scheduling.quartz.SimpleTriggerFactoryBeanproperty namejobDetail refjobDetail/propertyproperty namestartDelay value3000/propertyproperty namerepeatInterval value2000/property/bean -- !-- 第二种 CronTriggerBean支持到指定时间运行一次如每天12:00运行一次等。配置方式如下 --bean idcronTrigger classorg.springframework.scheduling.quartz.CronTriggerBeanproperty namejobDetail refjobDetail /!-- !—每天12:00运行一次 — --property namecronExpression value0 0 12 * * ? //bean !-- 第四步 配置调度工厂 --bean idschedulerFactoryBean lazy-inittrueclassorg.springframework.scheduling.quartz.SchedulerFactoryBeanproperty nametriggerslist!-- ref beantestTrigger/ref --ref beancronTrigger //list/property/bean
/beans
二 个人的定时任务实现
下面贴一下根据自己项目用到定时任务的简化版本使用的工具是idea
1 基本搭建
1.创建一个spring项目 2.pom文件引入必要依赖 ?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:contexthttp://www.springframework.org/schema/context xmlns:phttp://www.springframework.org/schema/pxmlns:aophttp://www.springframework.org/schema/aop xmlns:txhttp://www.springframework.org/schema/txxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsdconfig!-- https://blog.csdn.net/yk614294861/article/details/84324603 参考第二步作业类不需要继承特定基类 --!-- 任务初始化 第一步 要执行任务的作业类--bean idinitQuartzTask classcom.test.batch.scheduler.core.InitQuartzTaskref nameschedulerFactoryBeanschedulerFactoryBean/ref/bean!-- 第二步 将需要执行的定时任务注入JOB中 --bean idmethodInvokingJobDetailFactoryBean classorg.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBeanref nametargetObjectinitQuartzTask/ref!-- 任务类中需要执行的方法 也就是InitQuartzTask类中 scheduleTask方法--param nametargetMethodscheduleTask/param/bean!-- 第三步主定时计划 触发器将job注入 SimpleTriggerBean只支持按照一定频度调用任务如每隔x分终运行 --bean idmanagerTriggerBean classorg.springframework.scheduling.quartz.SimpleTriggerFactoryBeanref namejobDetailmethodInvokingJobDetailFactoryBean/refparam namestartDelay1000/param!-- 延时1秒执行任务 --param namerepeatInterval600000/param!-- 任务执行周期每隔 10分钟就启动加载任务执行 --/bean!-- 第四步注册SchedulerFactoryBean 配置调度工厂--bean idschedulerFactoryBean classorg.springframework.scheduling.quartz.SchedulerFactoryBeanparam nameapplicationContextSchedulerContextKeyapplicationContextKey/paramlist nametriggersrefmanagerTriggerBean/ref/list/bean
/config
/spring:beans
2 业务基本实现 2.1 主定时任务
bean idmanagerTriggerBean classorg.springframework.scheduling.quartz.SimpleTriggerFactoryBeanref namejobDetailmethodInvokingJobDetailFactoryBean/refparam namestartDelay1000/param!-- 延时1秒执行任务 --param namerepeatInterval600000/param!-- 任务执行周期每隔 10分钟就启动加载任务执行 --/bean 如图创建了SimpleTriggerFactoryBean类型主定时任务每10分钟一次读取定时任务表中的数据经过一定校验后维护调度器。
2.2 业务类定时任务 1项目的业务类定时任务及相关配置都存在指定数据库中大概内容为执行频率、是否允许并发、是否发送短信、禁止运行时间等辅助信息。业务如何运行的则只能通过修改业务代码实现。 2如何把定时任务加载到管理器中大概流程是主定时任务每10分钟一次从定时任务数据表中读取任务批量执行configTask方法将定时任务加载到Scheduler或进行更新。任务属性包括要数据表唯一主键、Cron表达式表达式、需要执行的任务名等信息。
优点不需要重启服务就能定时更新任务信息。
缺点需要通过数据库直接维护定时任务信息风险较高后面补了基本数据录入页面 数据库信息修改后需要等待主任务读取数据间隔为10分钟不能即刻生效项目后面进行了优化可以通过其他方式执行相关任务而不走定时两个渠道代码逻辑上互不影响业务上冲突另外解决。
public static void configTask(ScheduleTask task, Scheduler schedulerFactoryBean) {try {// 获取定时工厂类Scheduler scheduler schedulerFactoryBean;// 根据任务ID获取触发器keyTriggerKey triggerKey TriggerKey.triggerKey(task.getTaskId());// 获取触发器CronTrigger trigger (CronTrigger) scheduler.getTrigger(triggerKey);// 如果没有触发器则新建触发器if(Util.isNullOrEmpty(trigger)) {// 如果计划任务状态是启用状态则创建新的触发器if(1.equals(task.getTaskStatus())) {createTrigger(task, scheduler);}}else {// Trigger已存在那么更新相应的定时设置updateTrigger(task, scheduler, trigger, triggerKey);}} catch (SchedulerException e) {e.printStackTrace();}}
图中的task是定时任务信息
public class ScheduleTask {/** 任务ID */private String taskId;/** 任务名称 */private String taskName;/** 任务分组 */private String taskGroup;/** 任务状态 0禁用 1启用 2删除*/private String taskStatus;/** 任务运行时间表达式 */private String cronExpression;/** 任务描述 */private String description;/** 任务类 */private String targetObject;/** 任务方法 */private String targetMethod;/** 是否并发 0禁用 1启用 */private String concurrent;/** 任务开始时间 **/private Timestamp startTime;/**延期时间*/private long delayTime;/**操作员信息*/private String userInfo;
}
private static void createTrigger(ScheduleTask task, Scheduler scheduler) throws SchedulerException {// 根据任务是否并行创建不同的jobClass clazz 1.equals(task.getConcurrent()) ? QuartzTaskFactory.class: QuartzJobFactoryDisallowConcurrentExecution.class;// JobBuilder.newJob(自定义任务类).withIdentity(任务名称,组名).build()JobDetail jobDetail JobBuilder.newJob(clazz).withIdentity(task.getTaskId()).build();jobDetail.getJobDataMap().put(ScheduleTask, task);// 获取调度时间并赋值CronScheduleBuilder scheduleBuilder CronScheduleBuilder.cronSchedule(task.getCronExpression());CronTrigger trigger TriggerBuilder.newTrigger().withIdentity(task.getTaskId()).withSchedule(scheduleBuilder).build();// Scheduler可以将Trigger绑定到某一JobDetail中这样当Trigger触发时对应的Job就被执行。一个Job可以对应多个Trigger但一个Trigger只能对应一个Jobscheduler.scheduleJob(jobDetail, trigger);log.info(new Date() : 新建 task.getTaskName() 计划任务);}
private static void updateTrigger(ScheduleTask task, Scheduler scheduler, CronTrigger trigger,TriggerKey triggerKey) throws SchedulerException {// 任务为可用状态if(1.equals(task.getTaskStatus())) {// 如果触发器的任务时间跟数据库中任务的任务时间相同则不用更新设置if(!trigger.getCronExpression().equalsIgnoreCase(task.getCronExpression())) {CronScheduleBuilder scheduleBuilder CronScheduleBuilder.cronSchedule(task.getCronExpression());// 按新的cronExpression表达式重新构建triggertrigger trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();// 按新的trigger重新设置job执行scheduler.rescheduleJob(triggerKey, trigger);}}else {// 不可用 scheduler.pauseTrigger(trigger.getKey());// 停止触发器 scheduler.unscheduleJob(trigger.getKey());// 移除触发器 scheduler.deleteJob(trigger.getJobKey());// 删除任务}}
3 Quartz
Quartz的核心主要是调度器Scheduler、任务Job、触发器Trigger三部分 Quartz的核心是scheduler接口类而具体的实现类都是通过SchedulerFactory工厂类实现
Quartz API 主要包含了以下接口
Scheduler – 调度器将多个JobDetail和Trigger注册到Scheduler后通过Scheduler控制执行Job – 由调度器调度的任务需要实现的接口需要调度的具体内容。(主要实现其execute()方法)JobDetail – 用于绑定Job定义任务的实例包含了任务调度的方案和策略等属性。Trigger – 用于定义需要执行的任务和任务的执行时间。(包含SimpleTrigger和CronTrigger)JobBuilder – 用于定义/创建 JobDetail 实例。TriggerBuilder – 用于定义/创建 Trigger 对象。
3.1 任务Job、JobDetail、JobBuilder
需要执行的调度任务需要实现Job接口重写execute()方法Job中也只有这一个方法
public interface Job {void execute(JobExecutionContext context)throws JobExecutionException;}
DisallowConcurrentExecution
public class QuartzTaskFactory implements Job{private static Log log LogFactory.getLog(QuartzTaskFactory.class);Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {log.info(----------定时任务开始----------);ScheduleTask scheduleTask (ScheduleTask) context.getMergedJobDataMap().get(ScheduleTask);try {TaskUtils.invokMethod(scheduleTask,TaskUtils.getApplicationContext(context));} catch (Exception e) {log.error(e.getMessage());}log.info(----------定时任务结束---------- scheduleTask.getTaskName());}
}
补充DisallowConcurrentExecution这个注解不是必须的他的作用是禁止Quart的并发操作。一般针对于Job任务执行时间大于间隔时间的情况例如任务间隔为15s当时执行要30s不过这种情况建议修改业务或者时间间隔
创建JobBuilder定义JobDetail并生成唯一的任务标识JobKey
JobDetail jobDetail JobBuilder.newJob(clazz).withIdentity(task.getTaskId()).build(); // JobBuilder类里的JobDetail方法public JobDetail build() {JobDetailImpl job new JobDetailImpl();job.setJobClass(jobClass);job.setDescription(description);if(key null)key new JobKey(Key.createUniqueName(null), null);job.setKey(key); job.setDurability(durability);job.setRequestsRecovery(shouldRecover);if(!jobDataMap.isEmpty())job.setJobDataMap(jobDataMap);return job;} 3.2 触发器 Trigger、TriggerBuilder
整体来说触发器是用来告诉调度程序作业什么是否触发的例如下图中跟时间有关属性、JobKey属性(Trigger绑定的Job实例标识)、是否重复执行、执行间隔等 常见的Trigger主要是SimpleTrigger和CronTrigger
SimpleTrigger在一个指定时间段内执行一次作业任务或是在指定的时间间隔内多次执行作业任务。CronTrigger基于日历的作业调度器而不是像SimpleTrigger那样精确指定间隔时间因此SimpleTrigger能够实现的CronTrigger都能够实现所以普遍都用CronTrigger。
项目使用的就是CronTrigger先通过CronScheduleBuilder根据Cron表达式生成调度规则再通过TriggerBuilder构建CronTrigger类型的触发器最后用scheduler.scheduleJob(jobDetail, trigger);方法将cronTrigger触发器和任务jobDetail绑定。
由上述步骤可以看出Cron变换后需要重新构建CronScheduleBuilder再构建CronTrigger然后调用scheduler.rescheduleJob(triggerKey, CronTrigger);更新触发器才行。其中triggerKey是触发器的Key是通过TriggerKey.triggerKey(taskId)获取到的。
备注一个Job可以对应多个Trigger但一个Trigger只能对应一个Job
3.3 调度器Scheduler、SchedulerFactory、SchedulerFactoryBean
主要方法 启动、暂停、关闭等
项目使用SchedulerFactoryBean在afterPropertiesSet方法里初始化SchedulerFactory代码里默认生成StdSchedulerFactory这一个(DirectSchedulerFactory可以在代码里定制Schduler 参数)。并且查看相关代码可以知道还要设置