app开发者平台在数字化时代的重要性与发展趋势解析
1002
2022-09-26
springboot创建的web项目整合Quartz框架的项目实践
目录介绍基于springboot创建的web项目整合Quartz框架依次实现mvc三层
介绍
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的java组件或EJBs。Quartz的最新版本为Quartz 2.3.2。
quartz可以在某一个有规律的时间点干某件事,是一个任务调度框架,可以被集成到java的各种应用中使用,quartz框架可以支持分布式任务处理
基于springboot创建的web项目整合Quartz框架
整体代码结构
导入依赖
创建quartz_demo数据库,执行tables_mysql_innodb.sql文件创建对应表,下面是文件内容
#
# In your Quartz properties file, you'll need to set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#
#
# By: Ron Cordell - roncordell
# I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM.
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;
CREATE TABLE QRTZ_JOB_DETAILS(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(190) NOT NULL,
JOB_GROUP VARCHAR(190) 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))
ENGINE=InnoDB;
CREATE TABLE QRTZ_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
JOB_NAME VARCHAR(190) NOT NULL,
JOB_GROUP VARCHAR(190) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(190) NULL,
MISFIRE_INSTR SMALLINT(2) 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))
ENGINE=InnoDB;
CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_CRON_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
CRON_EXPRESSION VARCHAR(120) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
STR_PROP_1 VARCHAR(512) NULL,
STR_PROP_2 VARCHAR(512) NULL,
STR_PROP_3 VARCHAR(512) NULL,
INT_PROP_1 INT NULL,
INT_PROP_2 INT NULL,
LONG_PROP_1 BIGINT NULL,
LONG_PROP_2 BIGINT NULL,
DEC_PROP_1 NUMERIC(13,4) NULL,
DEC_PROP_2 NUMERIC(13,4) NULL,
BOOL_PROP_1 VARCHAR(1) NULL,
BOOL_PROP_2 VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_BLOB_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_CALENDARS (
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(190) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
ENGINE=InnoDB;
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_FIRED_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
INSTANCE_NAME VARCHAR(190) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(190) NULL,
JOB_GROUP VARCHAR(190) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
ENGINE=InnoDB;
CREATE TABLE QRTZ_SCHEDULER_STATE (
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(190) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
ENGINE=InnoDB;
CREATE TABLE QRTZ_LOCKS (
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME))
ENGINE=InnoDB;
CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
commit;
配置quartz
server:
port: ${PORT:12011}
servlet:
session:
timeout: 86400s # session有效期(xxx秒)
cookie:
http-only: false # 如果为true, 浏览器脚本将无法访问cookie
secure: false # 如果为true, 则仅通过https连接发送cookie, http无法携带cookie
context-path: # 程序上下文路径配置
spring:
application:
name: quartz-demo
aop:
proxy-target-class: true
auto: true
datasource:
url: jdbc:mysql://localhost:3306/quartz_demo
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
# 配置日期格式化
jackson:
date-format: yyyy-MM-dd HH:mm:ss #时间戳统一转换为指定格式
time-zone: GMT+8 # 时区修改为东8区
quartz:
# 将任务等保存化到数据库
job-store-type: jdbc
# 程序结束时会等待quartz相关的内容结束
wait-for-jobs-to-complete-on-shutdown: true
# QuartzScheduler启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录
overwrite-existing-jobs: true
properties:
org:
quartz:
# scheduler相关
scheduler:
# scheduler的实例名
instanceName: scheduler
instanceId: AUTO
# 持久化相关
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 表示数据库中相关表是QRTZ_开头的
tablePrefix: QRTZ_
useProperties: false
# 配置集群
# 是否加入集群
isClustered: true
# 容许的最大作业延长时间
clusterCheckinInterval: 20000
# 线程池相关
threadPool:
class: org.quartz.simpl.SimpleThreadPool
# 线程数
threadCount: 10
# 线程优先级
threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true
mybatis-plus:
global-config:
db-config:
logic-delete-field: is_deleted
logic-delete-value: 1
logic-not-delete-value: 0
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
level:
com.my.quartz: debug
添加sys_job表
CREATE TABLE `sys_job` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`job_id` varchar(100) DEFAULT NULL,
`job_name` varchar(255) DEFAULT NULL,
`job_group_name` varchar(255) DEFAULT NULL,
`invoke_target` varchar(255) NOT NULL,
`cron_expression` varchar(50) DEFAULT NULL,
`misfire_policy` varchar(255) DEFAULT NULL COMMENT 'cron计划策略0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行',
`status` varchar(10) DEFAULT NULL COMMENT '任务状态(0正常 1暂停)',
`concurrent` varchar(10) DEFAULT NULL COMMENT '是否并发执行(0允许 1禁止)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
写两条数据
依次实现mvc三层
mapper层的xml文件
t.id, t.job_id jobId, t.job_name jobName, t.job_group_name jobGroupName, t.invoke_target invokeTarget, t.cron_expression cronExpression, t.misfire_policy misfirePolicy, t.status, t.concurrent
mapper接口
/**
* Auto Generated
*
* @author :Boy
* @date :Created in 2022-06-18
* @description:
* @modified By:
*/
public interface SysJobMapper extends BaseMapper
}
service接口
public interface SysJobService extends IService
}
service接口实现
@Service
public class SysJobServiceImpl extends ServiceImpl
@Autowired
private Scheduler scheduler;
@Autowired
private ScheduleUtils scheduleUtils;
/**
* 项目启动时,初始化定时器
* 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据)
*/
@PostConstruct
public void init() throws SchedulerException, TaskException {
scheduler.clear();
List
for (SysJob job : jobList) {
scheduleUtils.createScheduleJob(scheduler, job);
}
}
}
controller代码
@RestController
@RequestMapping("/job")
public class SysJobController {
@Resource
private SysJobService sysJobService;
@Resource
private ScheduleUtils scheduleUtils;
@Resource
private Scheduler scheduler;
@PostMapping("/add")
public Object add(@RequestBody SysJob entity) throws SchedulerException, TaskException {
sysJobService.save(entity);
scheduleUtils.createScheduleJob(scheduler, entity);
return "ok";
}
}
ScheduleUtils 定时任务工具类
/**
* @Author ScholarTang
* @Date 2021/7/15 下午3:50
* @Desc 定时任务工具类
*/
@Component
public class ScheduleUtils {
@Autowired
private Scheduler scheduler;
/**
* 构建任务触发对象
*
* @param jobName
* @param jobGroup
* @return
*/
public TriggerKey getTriggerKey(String jobName, String jobGroup) {
return TriggerKey.triggerKey(jobName, jobGroup);
}
/**
* 构建任务键对象
*
* @param jobName
* @param jobGroup
* @return
*/
public JobKey getJobKey(String jobName, String jobGroup) {
return JobKey.jobKey(jobName, jobGroup);
}
/**
* 创建定时调度任务
*
*
* @param scheduler
* @param job
* @throws SchedulerException
* @throws TaskException
*/
public void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException {
// 构建job信息
String jobName = job.getJobId() + "_" + job.getJobName();
String jobGroupName = job.getJobGroupName();
//TODO 反射动态获取Job实现类
//构建job实例
JobDetail jobDetail = JobBuilder.newJob(QuartzJobImpl.class)
.withIdentity(getJobKey(jobName, jobGroupName))
.build();
jobDetail.getJobDataMap().put("QuartzJobExecutionData", job);
// 表达式调度构建器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);
// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobName, jobGroupName))
.withSchedule(cronScheduleBuilder).build();
// 放入参数,运行时的方法可以获取
jobDetail.getJobDataMap().put("QuartzJobExecutionData", job);
// 判断是否存在
if (scheduler.checkExists(getJobKey(jobName, jobGroupName))) {
// 防止创建时存在数据问题 先移除,然后在执行创建操作
scheduler.deleteJob(getJobKey(jobName, jobGroupName));
}
//创建定时任务调度
scheduler.scheduleJob(jobDetail, trigger);
// 暂停任务 规定 0启动 1暂停
if (job.getStatus().equals("1")) {
scheduler.pauseJob(getJobKey(jobName, jobGroupName));
}
}
/**
* 删除定时调度任务
*
* @param sysJob
* @throws SchedulerException
*/
public void deleteScheduleJob(SysJob sysJob) throws SchedulerException {
scheduler.deleteJob(getJobKey(sysJob.getJobId() + "_" + sysJob.getJobName(), sysJob.getJobGroupName()));
}
/**
* 设置定时任务策略
*
* @param sysJob
* @param cronScheduleBuilder
* @return
*/
public CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob sysJob, CronScheduleBuilder cronScheduleBuilder) throws TaskException {
switchhttp:// (sysJob.getMisfirePolicy()) {
case "0":
return cronScheduleBuilder;
case "1":
return cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires();
case "2":
return cronScheduleBuilder.withMisfireHandlingInstructionFireAndProceed();
case "3":
return cronScheduleBuilder.withMisfireHandlingInstructionDoNothing();
default:
throw new TaskException("任务失败策略 '" + sysJob.getMisfirePolicy()
+ "' 不能在cron计划任务中使用", TaskException.Code.CONFIG_ERROR);
}
}
}
创建一个Job实现类,只是一个简单实现类,没有对方法添加参数
@Slf4j
@Component
public class QuartzJobImpl implements Job {
@Autowired
private ApplicationContext context;
@SneakyThrows
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
SysJob sysJob = new SysJob();
BeanUtils.copyProperties(jobExecutionContext.getMergedJobDataMap().get("QuartzJobExecutionData"), sysJob);
log.info("正在执行任务");
String invokeTarget = sysJob.getInvokeTarget();
String beanName = invokeTarget.split("\\.")[0];
String methodName = invokeTarget.split("\\.")[1];
Object bean = context.getBean(beanName);
Class> clazz = bean.getClass();
Method method = clazz.getMethod(methodName);
method.invoke(bean);
log.info("已结束任务");
System.out.println();
}
}
创建最终任务执行类,执行函数级别的定时任务,数据库中的invoke_target是和这里放入spring中的名称相同的,quartz_target.hello最终执行的函数就是hello函数
@Slf4j
@Component("quartz_target")
public class QuartzJobExe {
@Resource
private Scheduler scheduler;
public void hello() throws Exception {
System.out.println("[job]实例执行...hello..." + System.currentTimeMillis());
}
public void action() throws Exception {
System.out.println("[job]实例执行...action..." + System.currentTimeMillis());
}
}
最终代码结构
启动spring boot之后的任务状态
使用postman工具类添加一个任务
然后在代码中添加一个对应的方法
重新启动springboot的运行结果
理论上使用这样的反射方式可以运行任何代码的
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~