springboot创建的web项目整合Quartz框架的项目实践

网友投稿 348 2022-07-21


目录介绍基于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框架

整体代码结构

导入依赖

org.springframework.boot

spring-boot-starter-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 implements SysJobService {

@Autowired

private Scheduler scheduler;

@Autowired

private ScheduleUtils scheduleUtils;

/**

* 项目启动时,初始化定时器

* 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据)

*/

@PostConstruct

public void init() throws SchedulerException, TaskException {

scheduler.clear();

List jobList = baseMapper.selectList(null);

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小时内删除侵权内容。

上一篇:Java服务调用RestTemplate与HttpClient的使用详解
下一篇:springboot读取resources下文件的方式详解
相关文章

 发表评论

暂时没有评论,来抢沙发吧~