本例是在springboot中通过读取数据库的定时任务信息,动态生成quartz定时任务
1、导入依赖:
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
#默认或是自己改名字都行
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
#如果使用集群,instanceId必须唯一,设置成AUTO
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000
#============================================================================
# Configure JobStore
#============================================================================
#
#org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
#存储方式使用JobStoreTX,也就是数据库
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#使用自己的配置文件
org.quartz.jobStore.useProperties:true
#数据库中quartz表的表名前缀
org.quartz.jobStore.tablePrefix:qrtz_
org.quartz.jobStore.dataSource:qzDS
#是否使用集群(如果项目只部署到 一台服务器,就不用了)
org.quartz.jobStore.isClustered = true
#============================================================================
# Configure Datasources
#============================================================================
#配置数据源
org.quartz.dataSource.qzDS.driver:com.mysql.jdbc.Driver
org.quartz.dataSource.qzDS.URL:jdbc:mysql://10.4.33.251:3306/ecif_orgin
org.quartz.dataSource.qzDS.user:reader1
org.quartz.dataSource.qzDS.password:Reader12341
org.quartz.dataSource.qzDS.maxConnection:103、在数据库中创建quartz相关的表
1)进入quartz的官网http://www.quartz-scheduler.org/,点击Downloads,下载后在目录\docs\dbTables下有常用数据库创建quartz表的脚本。
2)百度去搜创建quartz表
4、自定义MyJobFactory,解决spring不能在quartz中注入bean的问题
package com.nnfe.ecif.domain.bean;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
@Component
public class MyJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance); //这一步解决不能spring注入bean的问题
return jobInstance;
}
}5、创建调度器schedule
package com.nnfe.ecif.config;
import java.io.IOException;
import java.util.Properties;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import com.nnfe.ecif.domain.bean.MyJobFactory;
@Configuration
public class QuartzConfigration {
@Autowired
private MyJobFactory myJobFactory; //自定义的factory
//获取工厂bean
@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
try {
schedulerFactoryBean.setQuartzProperties(quartzProperties());
schedulerFactoryBean.setJobFactory(myJobFactory);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return schedulerFactoryBean;
}
//指定quartz.properties
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
//创建schedule
@Bean(name = "scheduler")
public Scheduler scheduler() {
return schedulerFactoryBean().getScheduler();
}
}
6、更新quartz中的任务
首先我们需要自己创建一张表,用来存放trigger的信息,然后从数据库读取这些信息来随时更新定时任务
现在我的数据库中有两个定时任务,注意:job_name存放的任务类的全路径,在quartz中通过jobName和jobGroup来确定trigger的唯一性,所以这两列为联合唯一索引。
接着创建实体类:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name = "c_schedule_triggers")
public class CScheduleTrigger {
@Id
@GenericGenerator(name = "mysqlNative", strategy = "native")
@GeneratedValue(generator = "mysqlNative")
private Integer id;
@Column
private String cron; //时间表达式
private String status; //使用状态 0:禁用 1:启用
private String jobName; //任务名称
private String jobGroup; //任务分组更新quartz中的任务
package com.nnfe.ecif.domain.service.impl;
import java.util.List;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import com.nnfe.ecif.domain.orm.w.CScheduleTriggerRepository;
import com.nnfe.ecif.domain.orm.w.CScheduleTrigger;
import com.nnfe.ecif.domain.service.ScheduleTriggerService;
@Service
public class ScheduleTriggerServiceImpl implements ScheduleTriggerService{
private static final Logger logger = LoggerFactory.getLogger(ScheduleTriggerServiceImpl.class);
@Autowired
private Scheduler scheduler;
@Autowired
private CScheduleTriggerRepository triggerRepository;
@Override
@Scheduled(cron="0 0 23:00 * * ?") //每天晚上11点调用这个方法来更新quartz中的任务
public void refreshTrigger() {
try {
//查询出数据库中所有的定时任务
List<CScheduleTrigger> jobList = triggerRepository.queryAll();
if(jobList!=null){
for(CScheduleTrigger scheduleJob : jobList){
String status = scheduleJob.getStatus(); //该任务触发器目前的状态
TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//说明本条任务还没有添加到quartz中
if (null == trigger) {
if(status.equals("0")){ //如果是禁用,则不用创建触发器
continue;
}
JobDetail jobDetail=null;
try {
//创建JobDetail(数据库中job_name存的任务全路径,这里就可以动态的把任务注入到JobDetail中)
jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(scheduleJob.getJobName()))
.withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()).build();
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob
.getCron());
//按新的cronExpression表达式构建一个新的trigger
trigger = TriggerBuilder.newTrigger().withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()).withSchedule(scheduleBuilder).build();
//把trigger和jobDetail注入到调度器
scheduler.scheduleJob(jobDetail, trigger);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else { //说明查出来的这条任务,已经设置到quartz中了
// Trigger已存在,先判断是否需要删除,如果不需要,再判定是否时间有变化
if(status.equals("0")){ //如果是禁用,从quartz中删除这条任务
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.deleteJob(jobKey);
continue;
}
String searchCron = scheduleJob.getCron(); //获取数据库的
String currentCron = trigger.getCronExpression();
if(!searchCron.equals(currentCron)){ //说明该任务有变化,需要更新quartz中的对应的记录
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(searchCron);
//按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(scheduleBuilder).build();
//按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
}
}
}
}
} catch (Exception e) {
logger.error("定时任务每日刷新触发器任务异常,在ScheduleTriggerServiceImpl的方法refreshTrigger中,异常信息:",e);
}
}7、自定义任务
@Component
public class MyTask1 implements Job{
//这里就可以通过spring注入bean了
@Autowired
private CScheduleTriggerRepository jobRepository;
@Autowired
private CScheduleRecordsRepository recordsRepository;
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
boolean isExecute = false; //是否已执行业务逻辑
boolean flag = false; //业务逻辑执行后返回结果
try{
//可以通过context拿到执行当前任务的quartz中的很多信息,如当前是哪个trigger在执行该任务
CronTrigger trigger = (CronTrigger) context.getTrigger();
String corn = trigger.getCronExpression();
String jobName = trigger.getKey().getName();
String jobGroup = trigger.getKey().getGroup();要搞清楚一个问题:从数据库读取任务信息动态生成定时任务,和把quartz持久化到数据库是没有关系的。
前者是我们自己定义的业务表,而后者是quartz使用自己的表来存储信息。持久化到数据库后,就算服务器重启或是多个quartz节点也没关系,因为他们共享数据库中的任务信息。
本文介绍了如何在SpringBoot应用中结合Quartz框架,通过数据库存储定时任务信息,实现动态生成及更新定时任务。内容包括导入Quartz依赖,创建相关数据库表,自定义MyJobFactory解决注入问题,创建任务实体类,以及阐述动态生成任务与Quartz持久化的关系。
&spm=1001.2101.3001.5002&articleId=75115913&d=1&t=3&u=d44dd0d9e61241cd98f674079d9c7f1b)
2033

被折叠的 条评论
为什么被折叠?



