使用自定义注解方式实现定时任务(全类型定时任务注解)
创建Factory对象(支持job中自动注入类)
java
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;
/**
* @author luos
* @date 2019/5/14
*/
@Component
public class QuartzJobFactory extends AdaptableJobFactory {
//这个对象Spring会帮我们自动注入进来
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}调度任务监听器
实现记录日志的功能
java
import com.commnetsoft.commons.utils.IpUtils;
import com.commnetsoft.dao.QrtzTaskRunLogDao;
import com.commnetsoft.model.QrtzTaskRunLogPo;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* <br> 任务调度 监听器
*
* @author luos
* @date 2020/7/9
*/
@Component
public class TaskJobListener implements JobListener {
private Logger logger = LoggerFactory.getLogger(TaskJobListener.class);
@Autowired
private QrtzTaskRunLogDao qrtzTaskRunLogDao;
@Override
public String getName() {
String name = getClass().getSimpleName();
return name;
}
@Override
public void jobToBeExecuted(JobExecutionContext context) {
Scheduler scheduler = context.getScheduler();
JobDetail jobDetail = context.getJobDetail();
Trigger trigger = context.getTrigger();
try {
QrtzTaskRunLogPo qrtzTaskRunLogPo = new QrtzTaskRunLogPo();
String hostAddress = IpUtils.getLocalIp();
qrtzTaskRunLogPo.setSchedname(scheduler.getSchedulerName());
qrtzTaskRunLogPo.setJobname(jobDetail.getKey().getName());
qrtzTaskRunLogPo.setJobgroup(jobDetail.getKey().getGroup());
qrtzTaskRunLogPo.setTriggername(trigger.getKey().getName());
qrtzTaskRunLogPo.setTriggergroup(trigger.getKey().getGroup());
qrtzTaskRunLogPo.setRuntype(QrtzTaskRunLogPo.run_auto);
qrtzTaskRunLogPo.setRunip(hostAddress);
qrtzTaskRunLogPo.setStarttime(new Date());
qrtzTaskRunLogDao.insertSelective(qrtzTaskRunLogPo);
Integer id = qrtzTaskRunLogPo.getId();
//该任务入库 数据id 传递到任务结束/异常 监听的方法中
context.put("id", id);
logger.info("任务[{}],即将开始运行", context.getJobDetail().getKey().getName());
} catch (SchedulerException e) {
e.printStackTrace();
}
}
@Override
public void jobExecutionVetoed(JobExecutionContext context) {
Object id = context.get("id");
if (null != id) {
QrtzTaskRunLogPo qrtzTaskRunLogPo = new QrtzTaskRunLogPo();
qrtzTaskRunLogPo.setId((Integer) id);
qrtzTaskRunLogPo.setEndtime(new Date());
qrtzTaskRunLogPo.setResultcode(QrtzTaskRunLogPo.run_fail);
qrtzTaskRunLogPo.setResultmsg("在 JobDetail 即将被执行,但又被 TriggerListener 否决了");
qrtzTaskRunLogDao.updateByPrimaryKeySelective(qrtzTaskRunLogPo);
logger.info("任务[{}]即将被执行,被 TriggerListener 否决了", context.getJobDetail().getKey().getName());
}
}
@Override
public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
Object id = context.get("id");
if (null != id) {
if (null == jobException) {
QrtzTaskRunLogPo qrtzTaskRunLogPo = new QrtzTaskRunLogPo();
qrtzTaskRunLogPo.setId((Integer) id);
qrtzTaskRunLogPo.setConsuming(Integer.valueOf((int) context.getJobRunTime()));
qrtzTaskRunLogPo.setEndtime(new Date());
qrtzTaskRunLogPo.setResultcode(QrtzTaskRunLogPo.run_success);
qrtzTaskRunLogDao.updateByPrimaryKeySelective(qrtzTaskRunLogPo);
logger.info("任务[{}],运行结束", context.getJobDetail().getKey().getName());
} else {
QrtzTaskRunLogPo qrtzTaskRunLogPo = new QrtzTaskRunLogPo();
qrtzTaskRunLogPo.setId((Integer) id);
qrtzTaskRunLogPo.setEndtime(new Date());
qrtzTaskRunLogPo.setResultcode(QrtzTaskRunLogPo.run_fail);
qrtzTaskRunLogPo.setResultmsg(jobException.getMessage());
qrtzTaskRunLogDao.updateByPrimaryKeySelective(qrtzTaskRunLogPo);
logger.info("任务[{}],因异常停止运行", context.getJobDetail().getKey().getName());
}
}
// String message = jobException.getMessage();
// String message1 = jobException.getCause().getMessage();
// Throwable cause = jobException.getCause();
}
}配置
读取配置文件并注册类和listener
java
@Autowired
DataSource dataSource;
@Bean
public SchedulerFactoryBean schedulerFactoryBean(QuartzJobFactory myJobFactory) throws Exception {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
schedulerFactoryBean.setDataSource(dataSource);
//使job实例支持spring 容器管理
schedulerFactoryBean.setOverwriteExistingJobs(true);
schedulerFactoryBean.setJobFactory(myJobFactory);
schedulerFactoryBean.setQuartzProperties(quartzProperties());
// 延迟60s启动quartz
schedulerFactoryBean.setStartupDelay(10);
return schedulerFactoryBean;
}
@Bean
public Scheduler scheduler(SchedulerFactoryBean schedulerFactoryBean) throws IOException, SchedulerException {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
//创建并注册一个全局的Job Listener
scheduler.getListenerManager().addJobListener(taskJobListener, EverythingMatcher.allJobs());
if (!scheduler.isShutdown()) {
scheduler.start();
log.info("调度器开始调度任务");
}
return scheduler;
}
/**
* 从quartz.properties文件中读取Quartz配置属性
*
* @return
* @throws IOException
*/
@Bean
public Properties quartzProperties() throws IOException {
ArrayList<Resource> configs = new ArrayList<>();
Resource baseConfig = new ClassPathResource(BASE_QUARTZ_CONFIG);
if (baseConfig.exists()) {
log.info("加载Quartz配置文件:{}", baseConfig.toString());
configs.add(baseConfig);
}
Resource extendConfig = new ClassPathResource(QUARTZ_CONFIG);
if (extendConfig.exists()) {
log.info("加载Quartz配置文件:{}", extendConfig.toString());
configs.add(extendConfig);
}
Resource extendConfig1 = new FileUrlResource(CONFIG_QUARTZ_CONFIG);
if (extendConfig1.exists()) {
log.info("加载Quartz配置文件:{}", extendConfig1.toString());
configs.add(extendConfig1);
}
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocations(configs.toArray(new Resource[configs.size()]));
propertiesFactoryBean.afterPropertiesSet();
Properties properties=propertiesFactoryBean.getObject();
//判断实例名是否手动设置
String instanceName=properties.getProperty("org.quartz.scheduler.instanceName");
if(StringUtils.isBlank(instanceName)){
properties.setProperty("org.quartz.scheduler.instanceName", applicationName);
}
return properties;
}properties
#quartz集群配置
# ===========================================================================
<NolebasePageProperties />
# Configure Main Scheduler Properties 调度器属性
# ===========================================================================
#调度标识名 集群中每一个实例都必须使用相同的名称,为空获取项目名
org.quartz.scheduler.instanceName=
#ID设置为自动获取 每一个必须不同
org.quartz.scheduler.instanceId=AUTO
#禁用quartz软件更新
org.quartz.scheduler.skipUpdateCheck=true
#============================================================================
# Configure ThreadPool
#============================================================================
#线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
#org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
#自定义任务线程池的实现类
org.quartz.threadPool.class =com.commnetsoft.TaskPool
##指定线程数,至少为1(无默认值)(一般设置为1-100直接的整数合适)
#org.quartz.threadPool.threadCount = 1
#设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
#org.quartz.threadPool.threadPriority = 5
#============================================================================
# Configure JobStore
#============================================================================
# 信息保存时间 默认值60秒
org.quartz.jobStore.misfireThreshold = 60000
#数据保存方式为数据库持久化
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#数据库代理类,一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以满足大部分数据库
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#JobDataMaps是否都为String类型
org.quartz.jobStore.useProperties = false
#数据库别名 随便取
org.quartz.jobStore.dataSource = qrtzDS
#表的前缀,默认QRTZ_
org.quartz.jobStore.tablePrefix = QRTZ_
#是否加入集群
org.quartz.jobStore.isClustered = true
#调度实例失效的检查时间间隔
org.quartz.jobStore.clusterCheckinInterval = 20000
#触发事务前是否需要拥有锁
org.quartz.jobStore.acquireTriggersWithinLock=true流程分析
项目启动时扫描自定义注解入库,并注册到调度器中(创建JobDetail->创建触发器->存入调度器),提供管理接口,并创建监听器,在调度任务执行前、取消、执行后执行。
自定义注解
java
import com.commnetsoft.annotation.TriggerCalendarInterval;
import java.lang.annotation.*;
/**
* 日历间隔触发器集合
* CalendarIntervalTrigger 触发器集合
*
* @author Brack.zhu
* @date 2020/6/23
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TriggerCalendarIntervalGroup {
TriggerCalendarInterval[] value() default {};
}
import com.commnetsoft.annotation.TriggerCron;
import java.lang.annotation.*;
/**
* Corn表达式触发器集合
* @author Brack.zhu
* @date 2020/6/23
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TriggerCronGroup {
TriggerCron[] value() default {};
}
import com.commnetsoft.annotation.TriggerDailyTimeInterval;
import java.lang.annotation.*;
/**
* 每天时间段间隔触发器集合
* DailyTimeIntervalTrigger触发器集合
*
* @author Brack.zhu
* @date 2020/6/23
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TriggerDailyTimeIntervalGroup {
TriggerDailyTimeInterval[] value() default {};
}
import com.commnetsoft.annotation.TriggerSimple;
import java.lang.annotation.*;
/**
* 简单的触发器集合
* @author Brack.zhu
* @date 2020/6/23
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TriggerSimpleGroup {
TriggerSimple[] value() default {};
}
import java.lang.annotation.*;
/**
* 任务job<br/>
* 任务要完整运行还需和触发器(Trigger)配合,一个任务支持多个触发器<br/>
* <p>如:
* <blockquote><pre>
* {@code
* @Task(desc = "测试任务")
* @CronTrigger(name = "1", cron = "0 0/1 * * * ?")
* @CronTrigger(name = "2", cron = "10 5 * * * ?")
* @CalendarIntervalTrigger(name = "3", repeatInterval = 1, repeatIntervalUnit = DateBuilder.IntervalUnit.HOUR)
* public class TestTask implements Job {//TODO}
* }
* </pre></blockquote>
* <p>
*
* @author luos
* @date 2019/7/17
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface JobTask {
/**
* 任务名称
* 默认为空使用类名 <br/>
*/
String name() default "";
/**
* 任务分组
* 默认为空使用包路径 <br/>
*/
String group() default "";
/**
* 任务描述
*/
String desc() default "";
/**
* 触发器JobDataMap<br/>
* 创建JobDataMap在@Configuration中使用@Bean创建的对象名
*
* @return
*/
String dataMap() default "";
}
import java.lang.annotation.*;
/**
* 触发器时间范围注解
* @author Brack.zhu
* @date 2020/6/23
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TimeLimit {
/**
* 开始时间,1970年1月1日00:00:00.000 GMT之后的毫秒数<br/>
* -1:创建时时间
* @return
*/
long start() default -1;
/**
* 结束时间,1970年1月1日00:00:00.000 GMT之后的毫秒数
* @return
*/
long end() default Long.MAX_VALUE;
}
import com.commnetsoft.annotation.group.TriggerCalendarIntervalGroup;
import org.quartz.DateBuilder;
import java.lang.annotation.*;
/**
* 日历间隔触发器
* 类似于SimpleTrigger,以一定的时间间隔执行的任务。 但是不同的是SimpleTrigger指定的时间间隔为毫秒,没办法指定每隔一个月执行一次(每月的时间间隔不是固定值),而CalendarIntervalTrigger支持的间隔单位有秒,分钟,小时,天,月,年,星期。
* <p>
* 相较于SimpleTrigger有两个优势:
* <p>
* 1、更方便,比如每隔1小时执行,你不用自己去计算1小时等于多少毫秒。
* <p>
* 2、支持不是固定长度的间隔,比如间隔为月和年。但劣势是精度只能到秒。
*
* @author Brack.zhu
* @date 2020/6/23
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(TriggerCalendarIntervalGroup.class)
public @interface TriggerCalendarInterval {
/**
* 触发器名称
*
* @return
*/
String name();
/**
* 间隔时间
*
* @return
*/
int repeatInterval();
/**
* 间隔时间单位类型
*
* @return
*/
DateBuilder.IntervalUnit repeatIntervalUnit();
/*--------------------------------以下非必填-------------------------------------------*/
/**
* 触发器描述
* @return
*/
String description() default "";
/**
* 触发器包含、排除 日历<br/>
* 详见
* {@link TriggerCron#modifiedByCalendar()}
*
* @return
*/
String modifiedByCalendar() default "";
/**
* 触发器有效期
*
* @return
*/
TimeLimit timeLimit() default @TimeLimit;
/**
* 触发器JobDataMap<br/>
* 创建JobDataMap在@Configuration中使用@Bean创建的对象名
*
* @return
*/
String dataMap() default "";
/**
* 错过调度策略机制<br/>
* MISFIRE_INSTRUCTION_DO_NOTHING<br/>
* <blockquote>
* 不触发等下次<br/>
* </blockquote>
* MISFIRE_INSTRUCTION_FIRE_ONCE_NOW<br/>
* <blockquote>
* 立刻执行一次,然后就按照正常的计划执行。<br/>
* </blockquote>
* MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY<br/>
* <blockquote>
* 忽略所有的超时状态,按照触发器的策略执行。
* </blockquote>
* <p>
* <p>
* withMisfireHandlingInstructionIgnoreMisfires
*
* @return
*/
int misfire() default org.quartz.CalendarIntervalTrigger.MISFIRE_INSTRUCTION_DO_NOTHING;
}
import com.commnetsoft.annotation.group.TriggerCronGroup;
import java.lang.annotation.*;
/**
* Corn表达式触发器
* @author Brack.zhu
* @date 2020/6/23
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(TriggerCronGroup.class)
public @interface TriggerCron {
/**
* 触发器名称
* 默认使用类名加触发器名称用 # 拼接 <br/>
* @return
*/
String name();
/**
* Corn表达式
* @return
*/
String cron();
/*--------------------------------以下非必填-------------------------------------------*/
/**
* 触发器描述
* @return
*/
String desc() default "";
/**
* 触发器包含、排除 日历<br/>
* 一般为节假日日历,如:<br/>
* 排除:任务定义工作日周一到周五运行,但是遇到法定节假日(国庆),任务需支持排除指定日期。<br/>
* 包含:任务定义工作日周一到周五运行,由于法定节假日需要调休,某个周六为工作日,任务需要支持包含指定日期。<br/>
* 创建日历在@Configuration中使用@Bean
* <p>如:
* <blockquote><pre>
* {@code
* @Bean
* public MonthlyCalendar myHolidays(){
* MonthlyCalendar calendar=new MonthlyCalendar();
* //排除
* calendar.setDayExcluded(20,true);
* //包含
* calendar.setDayExcluded(21,false);
* return calendar;
* }
* }
* </pre></blockquote>
* <p>
* 日历类型
* <blockquote><pre>
* AnnualCalendar 指定每年的哪一天。使用方式如上例。精度是【天】
* CronCalendar 指定Cron表达式。精度取决于Cron表达式,也就是最大精度可以【到秒】
* DailyCalendar 指定每天的时间段(rangeStartingTime,
* rangeEndingTime),格式是HH:MM[:SS[:mmm]]。也就是最大精度可以【到毫秒】
* HolidayCalendar 指定特定的日期,比如20140613。精度到【天】
* MonthlyCalendar 指定每月的几号。可选值为1-31。精度是【天】
* WeeklyCalendar 指定每星期的星期几,可选值比如为java.util.Calendar.SUNDAY。精度是【天】
* modifiedByCalendar
* </pre></blockquote>
* <p>
* @return
*/
String calendar() default "";
/**
* 触发器有效期
* @return
*/
TimeLimit timeLimit() default @TimeLimit;
/**
* 触发器JobDataMap<br/>
* 创建JobDataMap在@Configuration中使用@Bean创建的对象名
* @return
*/
String dataMap() default "";
/**
* 错过调度策略机制<br/>
* MISFIRE_INSTRUCTION_DO_NOTHING<br/>
* <blockquote>
* 不触发立即执行<br/>
* 等待下次Cron触发频率到达时刻开始按照Cron频率依次执行<br/>
* </blockquote>
* MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY<br/>
* <blockquote>
* 以错过的第一个频率时间立刻开始执行<br/>
* 重做错过的所有频率周期后<br/>
* 当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行<br/>
* </blockquote>
* MISFIRE_INSTRUCTION_FIRE_ONCE_NOW<br/>
* <blockquote>
* 以当前时间为触发频率立刻触发一次执行<br/>
* 然后按照Cron频率依次执行<br/>
* </blockquote>
* @return
*/
int misfire() default org.quartz.CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING;
}
import com.commnetsoft.annotation.group.TriggerDailyTimeIntervalGroup;
import org.quartz.DateBuilder;
import java.lang.annotation.*;
import java.util.Calendar;
/**
* 每天时间段间隔触发器
* 指定每天的某个时间段内,以一定的时间间隔执行任务。并且它可以支持指定星期。
* <p>
* 它适合的任务类似于:指定每天9:00 至 18:00 ,每隔50秒执行一次,并且只要周一至周五执行。
*
* @author Brack.zhu
* @date 2020/6/23
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(TriggerDailyTimeIntervalGroup.class)
public @interface TriggerDailyTimeInterval {
/**
* 触发器名称
* @return
*/
String name();
/**
* 每天任务开始时间<br/>
* 格式:HH:mm:ss<br/>
* 08:15:00
* @return
*/
String startTimeOfDay();
/**
* 每天任务结束时间<br/>
* 格式:HH:mm:ss<br/>
* 17:15:00
* @return
*/
String endTimeOfDay();
/**
* 一周内需要执行的星期几<br/>
* {@link Calendar#MONDAY}
* @return
*/
int[] daysOfWeek();
/**
* 间隔时间
* @return
*/
int repeatInterval();
/**
* 间隔时间单位类型
* @return
*/
DateBuilder.IntervalUnit repeatIntervalUnit();
/*--------------------------------以下非必填-------------------------------------------*/
/**
* 重复次数
* 执行次数为原始执行一次 + 重复次数
* @return
*/
int repeatCount() default -1;
/**
* 触发器描述
* @return
*/
String description() default "";
/**
* 触发器包含、排除 日历<br/>
* 详见
* {@link TriggerCron#modifiedByCalendar()}
*
* @return
*/
String modifiedByCalendar() default "";
/**
* 触发器有效期
* @return
*/
TimeLimit timeLimit() default @TimeLimit;
/**
* 触发器JobDataMap<br/>
* 创建JobDataMap在@Configuration中使用@Bean创建的对象名
* @return
*/
String dataMap() default "";
/**
* 错过调度策略机制<br/>
* MISFIRE_INSTRUCTION_DO_NOTHING<br/>
* <blockquote>
* 不触发等下次<br/>
* </blockquote>
* MISFIRE_INSTRUCTION_FIRE_ONCE_NOW<br/>
* <blockquote>
* 立刻执行一次,然后就按照正常的计划执行。<br/>
* </blockquote>
* MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY<br/>
* <blockquote>
* 忽略所有的超时状态,按照触发器的策略执行。
* </blockquote>
*
* @return
*/
int misfire() default org.quartz.DailyTimeIntervalTrigger.MISFIRE_INSTRUCTION_DO_NOTHING;
}
import com.commnetsoft.annotation.group.TriggerSimpleGroup;
import java.lang.annotation.*;
/**
* 简单的触发器<br/>
* 以一定的时间间隔(单位是毫秒)执行的任务。
*
* @author Brack.zhu
* @date 2020/6/23
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(TriggerSimpleGroup.class)
public @interface TriggerSimple {
/**
* 触发器名称
*
* @return
*/
String name();
/**
* 间隔时间,单位毫秒
*
* @return
*/
long repeatInterval();
/*--------------------------------以下非必填-------------------------------------------*/
/**
* 重复触发总次数
* 执行次数为原始执行一次 + 重复触发总次数
*
* @return
*/
int repeatCount() default -1;
/**
* 触发器描述
*
* @return
*/
String description() default "";
/**
* 触发器包含、排除 日历<br/>
* 详见
* {@link TriggerCron#modifiedByCalendar()}
*
* @return
*/
String modifiedByCalendar() default "";
/**
* 触发器有效期
*
* @return
*/
TimeLimit timeLimit() default @TimeLimit;
/**
* 触发器JobDataMap<br/>
* 创建JobDataMap在@Configuration中使用@Bean创建的对象名
*
* @return
*/
String dataMap() default "";
/**
* 错过调度策略机制<br/>
* MISFIRE_INSTRUCTION_FIRE_NOW<br/>
* <blockquote>
* 以当前时间为触发频率立即触发执行<br/>
* 执行至FinalTIme的剩余周期次数<br/>
* 以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到<br/>
* 调整后的FinalTime会略大于根据starttime计算的到的FinalTime值<br/>
* </blockquote>
* MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY<br/>
* <blockquote>
* 以错过的第一个频率时间立刻开始执行<br/>
* 重做错过的所有频率周期<br/>
* 当下一次触发频率发生时间大于当前时间以后,按照Interval的依次执行剩下的频率<br/>
* 共执行RepeatCount+1次<br/>
* </blockquote>
* MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT<br/>
* <blockquote>
* 不触发立即执行<br/>
* 等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数<br/>
* 以startTime为基准计算周期频率,并得到FinalTime<br/>
* 即使中间出现pause,resume以后保持FinalTime时间不变<br/>
* </blockquote>
* MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT<br/>
* <blockquote>
* 以当前时间为触发频率立即触发执行<br/>
* 执行至FinalTIme的剩余周期次数<br/>
* 以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到<br/>
* 调整后的FinalTime会略大于根据starttime计算的到的FinalTime值<br/>
* </blockquote>
* MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT<br/>
* <blockquote>
* 不触发立即执行<br/>
* 等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数<br/>
* 以startTime为基准计算周期频率,并得到FinalTime<br/>
* 即使中间出现pause,resume以后保持FinalTime时间不变<br/>
* </blockquote>
* MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT<br/>
* <blockquote>
* 以当前时间为触发频率立即触发执行<br/>
* 执行至FinalTIme的剩余周期次数<br/>
* 以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到<br/>
* 调整后的FinalTime会略大于根据starttime计算的到的FinalTime值<br/>
* </blockquote>
*
* @return
*/
int misfire() default org.quartz.SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW;
}项目运行扫描入库并注册到调度器
java
/**
* 项目启动扫描 @Task 注解 把定时任务刷到数据库
*
* @author luos
* @date 2019/7/17
*/
@Component
public class TaskRunner implements CommandLineRunner {
private Logger log = LoggerFactory.getLogger(TaskRunner.class);
@Autowired
private TaskInitService taskInitService;
@Autowired
private AmqpHelper amqpHelper;
@Value("${spring.application.name}")
private String applicationName;
@Autowired
private TaskService taskService;
@Override
public void run(String... args) throws Exception {
//发送调度器name
Object bean = SpringContextUtil.getBean("quartzProperties");
Properties properties = (Properties) bean;
//判断实例名是否手动设置
String instanceName = properties.getProperty("org.quartz.scheduler.instanceName");
if (StringUtils.isBlank(instanceName)) {
properties.setProperty("org.quartz.scheduler.instanceName", applicationName);
}
amqpHelper.sendToExchange(QuartzEvents.QUARTZ_SCHEDULER_NAME, instanceName);
List<String> taskList = new ArrayList<>();
List<Class<? extends Job>> classes = ClassScaner.scan(CoreConstant.Package.BASE, Job.class);
for (Class<? extends Job> clazz : classes) {
JobTask task = AnnotationUtils.getAnnotation(clazz, JobTask.class);
//获取扫描到任务类job名集合
if (isEmpty(task)) {
taskList.add(clazz.getName());
log.warn("初始化定时任务失败,未找到@Task注解:class:{}", clazz);
continue;
} else {
if (StringUtils.isNotBlank(task.name())) {
taskList.add(task.name());
} else {
taskList.add(clazz.getName());
}
}
//触发器各类型集合
Set<TriggerCron> cronTriggerGroup = AnnotationUtils.getDeclaredRepeatableAnnotations(clazz, TriggerCron.class);
Set<TriggerSimple> simpleTriggerGroup = AnnotationUtils.getDeclaredRepeatableAnnotations(clazz, TriggerSimple.class);
Set<TriggerDailyTimeInterval> dailyTimeIntervalTriggerGroup = AnnotationUtils.getDeclaredRepeatableAnnotations(clazz, TriggerDailyTimeInterval.class);
Set<TriggerCalendarInterval> calendarIntervalTriggerGroup = AnnotationUtils.getDeclaredRepeatableAnnotations(clazz, TriggerCalendarInterval.class);
if (isEmpty(cronTriggerGroup) && isEmpty(simpleTriggerGroup) && isEmpty(dailyTimeIntervalTriggerGroup) && isEmpty(calendarIntervalTriggerGroup)) {
log.warn("初始化定时任务失败,未找到相应的Trigger触发器注解:class:{}", clazz);
continue;
}
try {
taskInitService.initTask(clazz, task, cronTriggerGroup, simpleTriggerGroup, dailyTimeIntervalTriggerGroup, calendarIntervalTriggerGroup);
} catch (Exception e) {
log.error("初始化定时任务失败,class:{}", clazz, e);
throw new Exception("初始化定时任务失败,class:" + clazz, e);
}
}
//删除 调度器中不存在任务类的注册任务
List<JobKey> jobKeys = taskService.JobKeys();
for (JobKey jobKey : jobKeys) {
if (!taskList.contains(jobKey.getName())) {
taskService.delJob(jobKey.getName(), jobKey.getGroup());
}
}
}
/**
* 判断注解是否为空
*
* @param annotation
* @return
*/
public boolean isEmpty(Annotation annotation) {
if (null != annotation) {
return false;
}
return true;
}
/**
* 是否空注解集合
*
* @param annotations
* @return
*/
public boolean isEmpty(Set<? extends Annotation> annotations) {
if (CollectionUtils.isEmpty(annotations)) {
return true;
}
return false;
}
}存入数据库
java
import com.alibaba.fastjson.JSON;
import com.commnetsoft.QrtzError;
import com.commnetsoft.annotation.*;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.core.utils.SpringContextUtil;
import com.commnetsoft.dao.QrtzSimpleExistDao;
import com.commnetsoft.dao.QrtzTriggerDefaultDao;
import com.commnetsoft.exception.MicroRuntimeException;
import com.commnetsoft.model.QrtzSimpleExistPo;
import com.commnetsoft.model.QrtzTriggerDefaultPo;
import com.commnetsoft.service.builder.CronTriggerBuilder;
import com.commnetsoft.service.builder.StandardJobBuilder;
import org.apache.commons.collections.CollectionUtils;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* 任务初始化服务
*
* @author Brack.zhu
* @date 2020/6/24
*/
@Service
public class TaskInitService {
private Logger log = LoggerFactory.getLogger(TaskInitService.class);
@Autowired
private CronTriggerBuilder cronTriggerBuilder;
@Autowired
private StandardJobBuilder standardJobBuilder;
@Autowired
private TaskService taskService;
@Autowired
private QrtzTriggerDefaultDao qrtzTriggerDefaultDao;
@Autowired
private QrtzSimpleExistDao qrtzSimpleExistDao;
@Value("${spring.application.name}")
private String applicationName;
/**
* 初始化任务
*
* @param jobClazz 任务类
* @param task 任务注解
* @param cronTriggerGroup cron触发器集合
* @param simpleTriggerGroup 简单间隔触发器集合
* @param dailyTimeIntervalTriggerGroup 每天时间间隔触发器集合
* @param calendarIntervalTriggerGroup 日历间隔触发器集合
* @throws MicroRuntimeException
*/
public void initTask(Class<? extends Job> jobClazz, JobTask task,
Set<TriggerCron> cronTriggerGroup,
Set<TriggerSimple> simpleTriggerGroup,
Set<TriggerDailyTimeInterval> dailyTimeIntervalTriggerGroup,
Set<TriggerCalendarInterval> calendarIntervalTriggerGroup) throws MicroRuntimeException, SchedulerException {
//必须都构建成功
JobDetail jobDetail = standardJobBuilder.build(jobClazz, task);
Set<CronTrigger> cronTriggers = cronTriggerBuilder.build(jobDetail, cronTriggerGroup);
Set<SimpleTrigger> simpleTriggers = cronTriggerBuilder.buildSimple(jobDetail, simpleTriggerGroup);
Set<DailyTimeIntervalTrigger> dailyTimeIntervalTriggers = cronTriggerBuilder.buildDailyTimeInterval(jobDetail, dailyTimeIntervalTriggerGroup);
Set<CalendarIntervalTrigger> calendarIntervalTriggers = cronTriggerBuilder.buildCalendarInterval(jobDetail, calendarIntervalTriggerGroup);
//TODO 其他触发器类型
//以上构建都成功后进入创建流程,减少不必要的脏数据
if (!cronTriggers.isEmpty()) {
initTaskCron(jobDetail, cronTriggers);
}
if (!simpleTriggers.isEmpty()) {
initTaskSimple(jobDetail, simpleTriggers);
}
if (!dailyTimeIntervalTriggers.isEmpty()) {
initTaskDailyTime(jobDetail, dailyTimeIntervalTriggers);
}
if (!calendarIntervalTriggers.isEmpty()) {
initTaskCalendar(jobDetail, calendarIntervalTriggers);
}
}
public void initTaskCron(JobDetail job, Set<CronTrigger> cronTriggers) throws MicroRuntimeException, SchedulerException {
if (null == job || null == cronTriggers) {
throw new MicroRuntimeException(QrtzError.args_valid_failed);
}
String jobname = job.getKey().getName();
String jobgroup = job.getKey().getGroup();
//获取调度器中所有cron 触发器
List<? extends Trigger> triggers = taskService.getJobTrigger(jobname, jobgroup);
List<CronTrigger> cronTriggerList = new ArrayList<>();
for (Trigger trigger : triggers) {
if (trigger instanceof CronTrigger) {
CronTrigger cronTrigger = (CronTrigger) trigger;
cronTriggerList.add(cronTrigger);
}
}
//调度器中的触发器 在代码中没有 并且数据库中没有默认值(未被运维手动修改过) 删除该触发器
if (CollectionUtils.isNotEmpty(cronTriggerList)) {
for (CronTrigger cronTrigger : cronTriggerList) {
TriggerKey key1 = cronTrigger.getKey();
boolean isDef = isDefault(jobname, jobgroup, cronTrigger.getKey().getName(), cronTrigger.getKey().getGroup());
boolean equals = true;
for (CronTrigger t : cronTriggers) {
TriggerKey key2 = t.getKey();
if (key1.equals(key2)) {
equals = false;
}
}
if (equals && !isDef) {
taskService.delTigger(key1.getName(), key1.getGroup());
}
}
}
for (CronTrigger cronTrigger : cronTriggers) {
initTaskCron(job, cronTrigger);
}
}
public void initTaskCron(JobDetail job, CronTrigger cronTrigger) throws MicroRuntimeException, SchedulerException {
//任务名称 .任务分组
JobKey jobKey = job.getKey();
//判断实例名是否手动设置,获取实例名
String instanceName = geInstanceName();
String jobname = jobKey.getName();
String jobgroup = jobKey.getGroup();
//触发器 名称 分组 触发器数据(json)
TriggerKey triggerKey = cronTrigger.getKey();
String tigname = triggerKey.getName();
String tiggroup = triggerKey.getGroup();
//判断是否默认值
boolean isDef = isDefault(jobname, jobgroup, tigname, tiggroup);
if (isDef) {
QrtzTriggerDefaultPo qrtzTriggerDefaultPo = new QrtzTriggerDefaultPo();
qrtzTriggerDefaultPo.setJobname(jobname);
qrtzTriggerDefaultPo.setJobgroup(jobgroup);
qrtzTriggerDefaultPo.setTriggername(tigname);
qrtzTriggerDefaultPo.setTriggergroup(tiggroup);
QrtzTriggerDefaultPo qd = qrtzTriggerDefaultDao.selectOne(qrtzTriggerDefaultPo);
//默认值库里有数据 更新代码值 到默认值库
qd.setSchedname(instanceName);
qd.setTriggerdata(JSON.toJSONString(cronTrigger));
qd.setTriggertype(QrtzTriggerDefaultPo.tigger_cron);
qd.setCreatetime(new Date());
qrtzTriggerDefaultDao.updateByPrimaryKeySelective(qd);
} else {
//获取调度器中的触发器
Trigger schedulerTrigger = taskService.getSingleTrigger(tigname, tiggroup);
boolean update = cronTriggerBuilder.cronIsUpdate(cronTrigger, (CronTrigger) schedulerTrigger);
if (!update) {
if (taskService.checkJobExists(jobKey)) {
//任务存在 修改或新增 Trigger
taskService.modifyTrigger(job, cronTrigger);
} else {
//任务不存在 注册job和Trigger到调度器中
taskService.addNewJob(job, cronTrigger);
}
}
}
}
public void initTaskSimple(JobDetail job, Set<SimpleTrigger> simpleTriggers) throws MicroRuntimeException, SchedulerException {
//TODO
if (null == job || null == simpleTriggers) {
throw new MicroRuntimeException(QrtzError.args_valid_failed);
}
for (SimpleTrigger simpleTrigger : simpleTriggers) {
boolean isexsit = isexsit(job, simpleTrigger);
if (!isexsit) {
initTaskSimple(job, simpleTrigger);
//初始化后的simpletrigger组名 保存到库 ,作记录
advance(job, simpleTrigger);
}
}
}
public void initTaskSimple(JobDetail job, SimpleTrigger simpleTrigger) throws MicroRuntimeException, SchedulerException {
//任务名称 .任务分组
JobKey jobKey = job.getKey();
if (taskService.checkJobExists(jobKey)) {
//任务存在 修改或新增 Trigger
taskService.modifyTrigger(job, simpleTrigger);
} else {
//任务不存在 注册job和Trigger到调度器中
taskService.addNewJob(job, simpleTrigger);
}
}
public void initTaskCalendar(JobDetail job, Set<CalendarIntervalTrigger> calendarIntervalTriggers) throws MicroRuntimeException, SchedulerException {
if (null == job || null == calendarIntervalTriggers) {
throw new MicroRuntimeException(QrtzError.args_valid_failed);
}
for (CalendarIntervalTrigger calendarIntervalTrigger : calendarIntervalTriggers) {
boolean isexsit = isexsit(job, calendarIntervalTrigger);
if (!isexsit) {
initTaskCalendar(job, calendarIntervalTrigger);
//初始化后的simpletrigger组名 保存到库 ,作记录
advance(job, calendarIntervalTrigger);
}
}
}
public void initTaskCalendar(JobDetail job, CalendarIntervalTrigger calendarIntervalTrigger) throws MicroRuntimeException, SchedulerException {
//任务名称 .任务分组
JobKey jobKey = job.getKey();
//获取调度器中的触发器
if (taskService.checkJobExists(jobKey)) {
//任务存在 修改或新增 Trigger
taskService.modifyTrigger(job, calendarIntervalTrigger);
} else {
//任务不存在 注册job和Trigger到调度器中
taskService.addNewJob(job, calendarIntervalTrigger);
}
}
public void initTaskDailyTime(JobDetail job, Set<DailyTimeIntervalTrigger> dailyTimeIntervalTriggers) throws MicroRuntimeException, SchedulerException {
if (null == job || null == dailyTimeIntervalTriggers) {
throw new MicroRuntimeException(QrtzError.args_valid_failed);
}
for (DailyTimeIntervalTrigger dailyTimeIntervalTrigger : dailyTimeIntervalTriggers) {
boolean isexsit = isexsit(job, dailyTimeIntervalTrigger);
if (!isexsit) {
initTaskDailyTime(job, dailyTimeIntervalTrigger);
//初始化后的simpletrigger组名 保存到库 ,作记录
advance(job, dailyTimeIntervalTrigger);
}
}
}
public void initTaskDailyTime(JobDetail job, DailyTimeIntervalTrigger dailyTimeIntervalTriggers) throws MicroRuntimeException, SchedulerException {
//任务名称 .任务分组
JobKey jobKey = job.getKey();
if (taskService.checkJobExists(jobKey)) {
//任务存在 修改或新增 Trigger
taskService.modifyTrigger(job, dailyTimeIntervalTriggers);
} else {
//任务不存在 注册job和Trigger到调度器中
taskService.addNewJob(job, dailyTimeIntervalTriggers);
}
}
/**
* 获取 调度器实例名
*
* @return
*/
private String geInstanceName() {
Object bean = SpringContextUtil.getBean("quartzProperties");
Properties properties = (Properties) bean;
//判断实例名是否手动设置
String instanceName = properties.getProperty("org.quartz.scheduler.instanceName");
if (StringUtils.isBlank(instanceName)) {
instanceName = applicationName;
}
return instanceName;
}
/**
* 触发器默认值库里面是否 有数据 true : 有数据 false : 无数据
*
* @param jobname
* @param jobgroup
* @param triggername
* @return
*/
public boolean isDefault(String jobname, String jobgroup, String triggername, String triggergroup) {
boolean isDef = false;
QrtzTriggerDefaultPo qrtzTriggerDefaultPo = new QrtzTriggerDefaultPo();
qrtzTriggerDefaultPo.setJobname(jobname);
qrtzTriggerDefaultPo.setJobgroup(jobgroup);
qrtzTriggerDefaultPo.setTriggername(triggername);
qrtzTriggerDefaultPo.setTriggergroup(triggergroup);
List<QrtzTriggerDefaultPo> list = qrtzTriggerDefaultDao.select(qrtzTriggerDefaultPo);
if (CollectionUtils.isNotEmpty(list)) {
isDef = true;
}
return isDef;
}
/**
* trigger 是否已经初始化过,到库里面了
*
* @param job
* @param trigger
* @return
*/
private boolean isexsit(JobDetail job, Trigger trigger) {
boolean exsit = true;
String schedname = geInstanceName();
QrtzSimpleExistPo qrtzSimpleExistPo = new QrtzSimpleExistPo();
qrtzSimpleExistPo.setJobname(job.getKey().getName());
qrtzSimpleExistPo.setJobgroup(job.getKey().getGroup());
qrtzSimpleExistPo.setTriggername(trigger.getKey().getName());
qrtzSimpleExistPo.setTriggergroup(trigger.getKey().getGroup());
qrtzSimpleExistPo.setSchedname(schedname);
List<QrtzSimpleExistPo> list = qrtzSimpleExistDao.select(qrtzSimpleExistPo);
if (CollectionUtils.isEmpty(list)) {
exsit = false;
}
return exsit;
}
/**
* 初始化后的simpletrigger组名 保存到库 ,作记录
*
* @param job
* @param trigger
* @return
*/
private void advance(JobDetail job, Trigger trigger) {
String schedname = geInstanceName();
QrtzSimpleExistPo qrtzSimpleExistPo = new QrtzSimpleExistPo();
qrtzSimpleExistPo.setSchedname(schedname);
qrtzSimpleExistPo.setJobname(job.getKey().getName());
qrtzSimpleExistPo.setJobgroup(job.getKey().getGroup());
qrtzSimpleExistPo.setTriggername(trigger.getKey().getName());
qrtzSimpleExistPo.setTriggergroup(trigger.getKey().getGroup());
qrtzSimpleExistPo.setCreatetime(new Date());
qrtzSimpleExistDao.insertSelective(qrtzSimpleExistPo);
}
}构建接口
java
import com.commnetsoft.commons.utils.BeanUtils;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.core.utils.SpringContextUtil;
import org.quartz.JobDataMap;
import java.util.Map;
/**
* @author Brack.zhu
* @date 2020/6/28
*/
public interface IBuilder {
/**
* 构建JobDataMap对象
* @param pojoName
* @return
* @throws Exception
*/
default JobDataMap buildJobDataMap(String pojoName) throws Exception {
if (StringUtils.isNotEmpty(pojoName)) {
Object bean = SpringContextUtil.getBean(pojoName);
Map<String, Object> objectMap = BeanUtils.toMap(bean);
return new JobDataMap(objectMap);
}
return null;
}
}构建jobdetail
java
import com.commnetsoft.annotation.JobTask;
import com.commnetsoft.exception.MicroRuntimeException;
import org.quartz.Job;
import org.quartz.JobDetail;
/**
* @author Brack.zhu
* @date 2020/6/28
*/
public interface IJobBuilder extends IBuilder {
JobDetail build(Class<? extends Job> jobClazz, JobTask task) throws MicroRuntimeException;
/**
* 获取默认任务名称
* @param jobClazz
* @return
*/
default String getDefName(Class<? extends Job> jobClazz) {
return jobClazz.getName();
}
/**
* 获取默认任务分组
* @param jobClazz
* @return
*/
default String getDefGroup(Class<? extends Job> jobClazz) {
return jobClazz.getPackage().getName();
}
}java
import com.commnetsoft.QrtzError;
import com.commnetsoft.annotation.JobTask;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.exception.MicroRuntimeException;
import org.quartz.*;
import org.springframework.stereotype.Component;
/**
* 标准任务构建器
* @author Brack.zhu
* @date 2020/6/28
*/
@Component
public class StandardJobBuilder implements IJobBuilder {
@Override
public JobDetail build(Class<? extends Job> jobClazz, JobTask task) throws MicroRuntimeException {
if (null == jobClazz || null == task) {
throw new MicroRuntimeException(QrtzError.args_valid_failed);
}
try {
JobKey jobKey = JobKey.jobKey(getJobName(jobClazz, task), getJobGroup(jobClazz,task));
JobBuilder jobBuilder = JobBuilder.newJob(jobClazz).withIdentity(jobKey).withDescription(task.desc());
JobDataMap jobDataMap = buildJobDataMap(task.dataMap());
if(null!=jobDataMap){
jobBuilder.setJobData(jobDataMap);
}
return jobBuilder.storeDurably().build();
} catch (Exception e) {
throw new MicroRuntimeException(QrtzError.jon_create_failed,e);
}
}
/**
* 获取任务名称,空取类名
* @param jobClazz
* @param task
* @return
*/
public String getJobName(Class<? extends Job> jobClazz,JobTask task){
String name=task.name();
if(StringUtils.isBlank(name)){
name=getDefName(jobClazz);
}
return name;
}
/**
* 获取任务分组,为空使用包路径
* @param jobClazz
* @param task
* @return
*/
public String getJobGroup(Class<? extends Job> jobClazz,JobTask task){
String group=task.group();
if(StringUtils.isBlank(group)){
group=getDefGroup(jobClazz);
}
return group;
}
}构建触发器
java
import com.commnetsoft.annotation.*;
import com.commnetsoft.exception.MicroRuntimeException;
import org.quartz.JobDetail;
import org.quartz.Trigger;
import java.util.Date;
/**
* @author Brack.zhu
* @date 2020/6/24
*/
public interface ITriggerBuilder extends IBuilder {
<T extends Trigger> T build(JobDetail jobDetail, TriggerCron cronTrigger) throws MicroRuntimeException;
<T extends Trigger> T build(JobDetail jobDetail, TriggerSimple simpleTrigger) throws MicroRuntimeException;
<T extends Trigger> T build(JobDetail jobDetail, TriggerDailyTimeInterval cronTrigger) throws MicroRuntimeException;
<T extends Trigger> T build(JobDetail jobDetail, TriggerCalendarInterval cronTrigger) throws MicroRuntimeException;
default Date getStart(TimeLimit timeLimit) {
if (timeLimit.start() < 0) {
return new Date();
}
return new Date(timeLimit.start());
}
default Date getEnd(TimeLimit timeLimit) {
return new Date(timeLimit.end());
}
/**
* 构建完整(入库)的触发器名称
*
* @param jobDetail
* @param triggerName
* @return
*/
default String buildRealName(JobDetail jobDetail, String triggerName) {
String className = jobDetail.getJobClass().getName();
return className + "#" + triggerName;
}
}java
import com.commnetsoft.QrtzError;
import com.commnetsoft.annotation.TriggerCalendarInterval;
import com.commnetsoft.annotation.TriggerCron;
import com.commnetsoft.annotation.TriggerDailyTimeInterval;
import com.commnetsoft.annotation.TriggerSimple;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.exception.MicroRuntimeException;
import org.quartz.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* @author Brack.zhu
* @date 2020/6/24
*/
@Component
public class CronTriggerBuilder implements ITriggerBuilder {
public <T extends Trigger> Set<T> build(JobDetail jobDetail, Set<TriggerCron> triggerCronGroup) throws MicroRuntimeException {
if (null == jobDetail || null == triggerCronGroup) {
throw new MicroRuntimeException(QrtzError.args_valid_failed);
}
Set<T> triggers = new HashSet<>();
for (TriggerCron cronTrigger : triggerCronGroup) {
CronTrigger trigger = build(jobDetail, cronTrigger);
triggers.add((T) trigger);
}
return triggers;
}
@Override
public CronTrigger build(JobDetail jobDetail, TriggerCron cronTrigger) throws MicroRuntimeException {
if (null == jobDetail || null == cronTrigger) {
throw new MicroRuntimeException(QrtzError.args_valid_failed);
}
try {
TriggerKey triggerKey = TriggerKey.triggerKey(getName(jobDetail, cronTrigger), jobDetail.getKey().getGroup());
CronScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule(cronTrigger.cron());
int misfire = cronTrigger.misfire();
// 设置任务misfire后 补偿执行策略
schedBuilder = setCronStrategy(misfire, schedBuilder);
TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(schedBuilder)
.startAt(getStart(cronTrigger.timeLimit())).endAt(getEnd(cronTrigger.timeLimit())).withDescription(cronTrigger.desc());
JobDataMap jobDataMap = buildJobDataMap(cronTrigger.dataMap());
if (null != jobDataMap) {
triggerBuilder.usingJobData(jobDataMap);
}
//触发器包含、排除 日历
String modifiedByCalendar = cronTrigger.calendar();
if (StringUtils.isNotEmpty(modifiedByCalendar)) {
triggerBuilder.modifiedByCalendar(modifiedByCalendar);
}
return (CronTrigger) triggerBuilder.forJob(jobDetail.getKey()).build();
} catch (Exception e) {
throw new MicroRuntimeException(QrtzError.trigger_create_failed, e);
}
}
/**
* cron 根据自定义传入参数 设置任务misfire后 补偿执行策略
*
* @param misfire
* @param schedBuilder
* @return
*/
public CronScheduleBuilder setCronStrategy(int misfire, CronScheduleBuilder schedBuilder) {
if (misfire == CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING) {
schedBuilder.withMisfireHandlingInstructionDoNothing();
} else if (misfire == CronTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) {
schedBuilder.withMisfireHandlingInstructionIgnoreMisfires();
} else if (misfire == CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) {
schedBuilder.withMisfireHandlingInstructionFireAndProceed();
}
return schedBuilder;
}
/**
* simple 根据自定义传入参数 设置任务misfire后 补偿执行策略
*
* @param misfire
* @param schedBuilder
* @return
*/
public SimpleScheduleBuilder setSimpleStrategy(int misfire, SimpleScheduleBuilder schedBuilder) {
if (misfire == SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW) {
schedBuilder.withMisfireHandlingInstructionFireNow();
} else if (misfire == SimpleTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) {
schedBuilder.withMisfireHandlingInstructionIgnoreMisfires();
} else if (misfire == SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT) {
schedBuilder.withMisfireHandlingInstructionNextWithExistingCount();
} else if (misfire == SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT) {
schedBuilder.withMisfireHandlingInstructionNowWithExistingCount();
} else if (misfire == SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT) {
schedBuilder.withMisfireHandlingInstructionNextWithRemainingCount();
} else if (misfire == SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT) {
schedBuilder.withMisfireHandlingInstructionNowWithRemainingCount();
}
return schedBuilder;
}
/**
* DailyTimeInterval 根据自定义传入参数 设置任务misfire后 补偿执行策略
*
* @param misfire
* @param schedBuilder
* @return
*/
public DailyTimeIntervalScheduleBuilder setDailyTimeIntervalStrategy(int misfire, DailyTimeIntervalScheduleBuilder schedBuilder) {
if (misfire == DailyTimeIntervalTrigger.MISFIRE_INSTRUCTION_DO_NOTHING) {
schedBuilder.withMisfireHandlingInstructionDoNothing();
} else if (misfire == DailyTimeIntervalTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) {
schedBuilder.withMisfireHandlingInstructionFireAndProceed();
} else if (misfire == DailyTimeIntervalTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) {
schedBuilder.withMisfireHandlingInstructionIgnoreMisfires();
}
return schedBuilder;
}
/**
* simple 根据自定义传入参数 设置任务misfire后 补偿执行策略
*
* @param misfire
* @param schedBuilder
* @return
*/
public CalendarIntervalScheduleBuilder setCalendarIntervalStrategy(int misfire, CalendarIntervalScheduleBuilder schedBuilder) {
if (misfire == CalendarIntervalTrigger.MISFIRE_INSTRUCTION_DO_NOTHING) {
schedBuilder.withMisfireHandlingInstructionDoNothing();
} else if (misfire == CalendarIntervalTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) {
schedBuilder.withMisfireHandlingInstructionFireAndProceed();
} else if (misfire == CalendarIntervalTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) {
schedBuilder.withMisfireHandlingInstructionIgnoreMisfires();
}
return schedBuilder;
}
/**
* 判断 调度器中cron触发器 与 代码中的cron触发器 是否一致 true :一致 false :不一致
*
* @param trigger1
* @param trigger2
* @return
*/
public boolean cronIsUpdate(CronTrigger trigger1, CronTrigger trigger2) {
boolean isDef = true;
if (null == trigger1 || null == trigger2) {
return false;
}
//key
if (!trigger1.equals(trigger2)) {
isDef = false;
}
//表达式
if (!trigger1.getCronExpression().equals(trigger2.getCronExpression())) {
isDef = false;
}
//描述
if (!trigger1.getDescription().equals(trigger2.getDescription())) {
isDef = false;
}
//补偿策略
if (!(trigger1.getMisfireInstruction() == trigger2.getMisfireInstruction())) {
isDef = false;
}
return isDef;
}
/**
* 判断 调度器中cron触发器 与 代码中的cron触发器 是否一致 true :一致 false :不一致
*
* @param trigger1
* @param trigger2
* @return
*/
public boolean simpleIsUpdate(SimpleTrigger trigger1, SimpleTrigger trigger2) {
boolean isDef = true;
if (null == trigger1 || null == trigger2) {
return false;
}
//key
if (!trigger1.equals(trigger2)) {
isDef = false;
}
//表达式
if (!(trigger1.getRepeatCount() == (trigger2.getRepeatCount()))) {
isDef = false;
}
//表达式
if (!(trigger1.getRepeatInterval() == (trigger2.getRepeatInterval()))) {
isDef = false;
}
//描述
if (!trigger1.getDescription().equals(trigger2.getDescription())) {
isDef = false;
}
//补偿策略
if (!(trigger1.getMisfireInstruction() == trigger2.getMisfireInstruction())) {
isDef = false;
}
return isDef;
}
/**
* 获取触发器名称,使用类名加触发器名称唯一
*
* @return
*/
public String getName(JobDetail jobDetail, TriggerCron cronTrigger) {
String name = cronTrigger.name();
return buildRealName(jobDetail, name);
}
/**
* 简单触发器的构建
*
* @return
*/
public <T extends Trigger> Set<T> buildSimple(JobDetail jobDetail, Set<TriggerSimple> triggerSimpleGroup) throws MicroRuntimeException {
if (null == jobDetail || null == triggerSimpleGroup) {
throw new MicroRuntimeException(QrtzError.args_valid_failed);
}
Set<T> triggers = new HashSet<>();
for (TriggerSimple simpleTrigger : triggerSimpleGroup) {
SimpleTrigger trigger = build(jobDetail, simpleTrigger);
triggers.add((T) trigger);
}
return triggers;
}
/**
* 简单触发器的构建
*
* @return
*/
@Override
public SimpleTrigger build(JobDetail jobDetail, TriggerSimple simpleTrigger) throws MicroRuntimeException {
if (null == jobDetail || null == simpleTrigger) {
throw new MicroRuntimeException(QrtzError.args_valid_failed);
}
TriggerBuilder simpleTriggerBuilder = null;
try {
TriggerKey triggerKey = TriggerKey.triggerKey(getName(jobDetail, simpleTrigger), jobDetail.getKey().getGroup());
SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(simpleTrigger.repeatInterval());
if (simpleTrigger.repeatCount() > -1) {
simpleScheduleBuilder.withRepeatCount(simpleTrigger.repeatCount());
}
int misfire = simpleTrigger.misfire();
// 设置任务misfire后 补偿执行策略
simpleScheduleBuilder = setSimpleStrategy(misfire, simpleScheduleBuilder);
simpleTriggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(simpleScheduleBuilder)
.startAt(getStart(simpleTrigger.timeLimit()))
.endAt(getEnd(simpleTrigger.timeLimit()))
.withDescription(simpleTrigger.description());
JobDataMap jobDataMap = buildJobDataMap(simpleTrigger.dataMap());
if (null != jobDataMap) {
simpleTriggerBuilder.usingJobData(jobDataMap);
}
//触发器包含、排除 日历
String modifiedByCalendar = simpleTrigger.modifiedByCalendar();
if (StringUtils.isNotEmpty(modifiedByCalendar)) {
simpleTriggerBuilder.modifiedByCalendar(modifiedByCalendar);
}
return (SimpleTrigger) simpleTriggerBuilder.forJob(jobDetail.getKey()).build();
} catch (Exception e) {
throw new MicroRuntimeException(QrtzError.trigger_create_failed, e);
}
}
/**
* 获取触发器名称,使用类名加触发器名称唯一
*
* @return
*/
public String getName(JobDetail jobDetail, TriggerSimple simpleTrigger) {
String name = simpleTrigger.name();
return buildRealName(jobDetail, name);
}
/**
* 日期触发器的构建
*
* @return
*/
public <T extends Trigger> Set<T> buildDailyTimeInterval(JobDetail jobDetail, Set<TriggerDailyTimeInterval> TriggerDailyTimeIntervalGroup) throws MicroRuntimeException {
if (null == jobDetail || null == TriggerDailyTimeIntervalGroup) {
throw new MicroRuntimeException(QrtzError.args_valid_failed);
}
Set<T> triggers = new HashSet<>();
for (TriggerDailyTimeInterval triggerDailyTimeInterval : TriggerDailyTimeIntervalGroup) {
DailyTimeIntervalTrigger trigger = build(jobDetail, triggerDailyTimeInterval);
triggers.add((T) trigger);
}
return triggers;
}
/**
* 日期触发器的构建
*
* @return
*/
@Override
public DailyTimeIntervalTrigger build(JobDetail jobDetail, TriggerDailyTimeInterval triggerDailyTimeInterval) throws MicroRuntimeException {
if (null == jobDetail || null == triggerDailyTimeInterval) {
throw new MicroRuntimeException(QrtzError.args_valid_failed);
}
TriggerBuilder triggerBuilder = null;
try {
String[] start = triggerDailyTimeInterval.startTimeOfDay().split(":");
String[] end = triggerDailyTimeInterval.endTimeOfDay().split(":");
int[] week = triggerDailyTimeInterval.daysOfWeek();
//先将int数组转换为数值流
IntStream stream = Arrays.stream(week);
Stream<Integer> integerStream = stream.boxed();
Integer[] days = integerStream.toArray(Integer[]::new);
TriggerKey triggerKey = TriggerKey.triggerKey(getName(jobDetail, triggerDailyTimeInterval), jobDetail.getKey().getGroup());
DailyTimeIntervalScheduleBuilder dailyTimeIntervalScheduleBuilder = DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()
.withInterval(triggerDailyTimeInterval.repeatInterval(), triggerDailyTimeInterval.repeatIntervalUnit())
.startingDailyAt(new TimeOfDay(Integer.parseInt(start[0]), Integer.parseInt(start[1]), Integer.parseInt(start[2])))
.endingDailyAt(new TimeOfDay(Integer.parseInt(end[0]), Integer.parseInt(end[1]), Integer.parseInt(end[2])))
.onDaysOfTheWeek(days);
if (triggerDailyTimeInterval.repeatCount() > -1) {
dailyTimeIntervalScheduleBuilder.withRepeatCount(triggerDailyTimeInterval.repeatCount());
}
int misfire = triggerDailyTimeInterval.misfire();
// 设置任务misfire后 补偿执行策略
dailyTimeIntervalScheduleBuilder = setDailyTimeIntervalStrategy(misfire, dailyTimeIntervalScheduleBuilder);
triggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(dailyTimeIntervalScheduleBuilder)
.startAt(getStart(triggerDailyTimeInterval.timeLimit()))
.endAt(getEnd(triggerDailyTimeInterval.timeLimit()))
.withDescription(triggerDailyTimeInterval.description());
JobDataMap jobDataMap = buildJobDataMap(triggerDailyTimeInterval.dataMap());
if (null != jobDataMap) {
triggerBuilder.usingJobData(jobDataMap);
}
//触发器包含、排除 日历
String modifiedByCalendar = triggerDailyTimeInterval.modifiedByCalendar();
if (StringUtils.isNotEmpty(modifiedByCalendar)) {
triggerBuilder.modifiedByCalendar(modifiedByCalendar);
}
return (DailyTimeIntervalTrigger) triggerBuilder.forJob(jobDetail.getKey()).build();
} catch (Exception e) {
throw new MicroRuntimeException(QrtzError.trigger_create_failed, e);
}
}
/**
* 获取触发器名称,使用类名加触发器名称唯一
*
* @return
*/
public String getName(JobDetail jobDetail, TriggerDailyTimeInterval triggerDailyTimeInterval) {
String name = triggerDailyTimeInterval.name();
return buildRealName(jobDetail, name);
}
/**
* 日历触发器的构建
*
* @return
*/
public <T extends Trigger> Set<T> buildCalendarInterval(JobDetail jobDetail, Set<TriggerCalendarInterval> triggerCalendarIntervals) throws MicroRuntimeException {
if (null == jobDetail || null == triggerCalendarIntervals) {
throw new MicroRuntimeException(QrtzError.args_valid_failed);
}
Set<T> triggers = new HashSet<>();
for (TriggerCalendarInterval triggerDailyTimeInterval : triggerCalendarIntervals) {
CalendarIntervalTrigger trigger = build(jobDetail, triggerDailyTimeInterval);
triggers.add((T) trigger);
}
return triggers;
}
/**
* 日历触发器的构建
*
* @return
*/
@Override
public CalendarIntervalTrigger build(JobDetail jobDetail, TriggerCalendarInterval triggerCalendarInterval) throws MicroRuntimeException {
if (null == jobDetail || null == triggerCalendarInterval) {
throw new MicroRuntimeException(QrtzError.args_valid_failed);
}
TriggerBuilder simpleTriggerBuilder = null;
try {
TriggerKey triggerKey = TriggerKey.triggerKey(getName(jobDetail, triggerCalendarInterval), jobDetail.getKey().getGroup());
CalendarIntervalScheduleBuilder calendarIntervalScheduleBuilder = CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
.withInterval(triggerCalendarInterval.repeatInterval(), triggerCalendarInterval.repeatIntervalUnit());
int misfire = triggerCalendarInterval.misfire();
// 设置任务misfire后 补偿执行策略
calendarIntervalScheduleBuilder = setCalendarIntervalStrategy(misfire, calendarIntervalScheduleBuilder);
simpleTriggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(calendarIntervalScheduleBuilder)
.startAt(getStart(triggerCalendarInterval.timeLimit()))
.endAt(getEnd(triggerCalendarInterval.timeLimit()))
.withDescription(triggerCalendarInterval.description());
JobDataMap jobDataMap = buildJobDataMap(triggerCalendarInterval.dataMap());
if (null != jobDataMap) {
simpleTriggerBuilder.usingJobData(jobDataMap);
}
//触发器包含、排除 日历
String modifiedByCalendar = triggerCalendarInterval.modifiedByCalendar();
if (StringUtils.isNotEmpty(modifiedByCalendar)) {
simpleTriggerBuilder.modifiedByCalendar(modifiedByCalendar);
}
return (CalendarIntervalTrigger) simpleTriggerBuilder.forJob(jobDetail.getKey()).build();
} catch (Exception e) {
throw new MicroRuntimeException(QrtzError.trigger_create_failed, e);
}
}
/**
* 获取触发器名称,使用类名加触发器名称唯一
*
* @return
*/
public String getName(JobDetail jobDetail, TriggerCalendarInterval triggerCalendarInterval) {
String name = triggerCalendarInterval.name();
return buildRealName(jobDetail, name);
}
}定时任务相关管理
java
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.commnetsoft.commons.Pager;
import com.commnetsoft.commons.utils.DateUtils;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.core.utils.PagerUtils;
import com.commnetsoft.core.utils.SpringContextUtil;
import com.commnetsoft.dao.QrtzTriggerDefaultDao;
import com.commnetsoft.model.QrtzTaskLogPo;
import com.commnetsoft.model.QrtzTaskRunLogPo;
import com.commnetsoft.model.QrtzTriggerDefaultPo;
import com.commnetsoft.quartz.model.*;
import org.omg.CORBA.Object;
import org.quartz.Calendar;
import org.quartz.*;
import org.quartz.impl.calendar.BaseCalendar;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.impl.triggers.CalendarIntervalTriggerImpl;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.quartz.impl.triggers.DailyTimeIntervalTriggerImpl;
import org.quartz.impl.triggers.SimpleTriggerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import java.text.ParseException;
import java.util.*;
/**
* @author luos
* @date 2019/5/14
*/
@Service
public class TaskService {
private Logger log = LoggerFactory.getLogger(TaskService.class);
@Autowired
private Scheduler scheduler;
@Autowired
private TaskInitService taskInitService;
@Autowired
private QrtzTriggerDefaultDao qrtzTriggerDefaultDao;
@Autowired
private QrtzTaskRunLogService qrtzTaskRunLogService;
@Autowired
private QrtzTaskLogService qrtzTaskLogService;
/**
* 任务已经存在于调度器中 新增或修改触发器
*
* @param jobDetail
* @param trigger
*/
public void modifyTrigger(JobDetail jobDetail, Trigger trigger) {
try {
//处理 包含/排除 日历
addCalendarName(trigger);
if (!checkTriggerExists(trigger.getKey())) {
addJob(jobDetail);
addTrigger(trigger);
} else {
updateJob(jobDetail, trigger);
log.info("该定时任务({})的触发器({})已经存在", jobDetail.getKey().getName(), trigger.getKey().getName());
}
} catch (SchedulerException e) {
log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
e.printStackTrace();
}
}
/**
* 任务 注册到 调度器中
*
* @param jobDetail
*/
public void addJob(JobDetail jobDetail) {
try {
scheduler.addJob(jobDetail, true);
} catch (SchedulerException e) {
log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
e.printStackTrace();
}
}
/**
* 为 任务增加触发器
*
* @param trigger
*/
public void addTrigger(Trigger trigger) {
try {
//处理 包含/排除 日历
addCalendarName(trigger);
scheduler.scheduleJob(trigger);
} catch (SchedulerException e) {
log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
e.printStackTrace();
}
}
/**
* 新的定时任务绑定触发器 注册到 触发器
*
* @param jobDetail
*/
public void addNewJob(JobDetail jobDetail, Trigger trigger) {
try {
//处理 包含/排除 日历
addCalendarName(trigger);
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
e.printStackTrace();
}
}
/**
* 修改定时任务
*
* @param jobDetail
* @param trigger
*/
public void updateJob(JobDetail jobDetail, Trigger trigger) {
try {
//处理 包含/排除 日历
addCalendarName(trigger);
if (checkTriggerExists(trigger.getKey())) {
HashSet<Trigger> triggerSet = new HashSet<>();
triggerSet.add(trigger);
scheduler.scheduleJob(jobDetail, triggerSet, true);
} else {
log.error("该定时任务({})的触发器不存在", jobDetail.getKey().getName());
}
} catch (SchedulerException e) {
log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
e.printStackTrace();
}
}
/**
* 通过jobName 和 组名删除任务
*
* @param jobName
* @param jobGroup
*/
public void delJob(String jobName, String jobGroup) {
try {
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
if (checkJobExists(jobKey)) {
scheduler.deleteJob(jobKey);
log.info("delete Job, jobGroup:{}, jobName:{}", jobGroup, jobName);
}
} catch (SchedulerException e) {
log.error(e.getMessage());
}
}
/**
* 通过jjobKeys 删除多个任务
*/
public void delJobs(List<JobKey> jobKeys) {
try {
scheduler.deleteJobs(jobKeys);
} catch (SchedulerException e) {
log.error(e.getMessage());
}
}
/**
* 通过triggerName 和 组名删除任务的触发器
*
* @param triggerName
* @param groupName
*/
public void delTigger(String triggerName, String groupName) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, groupName);
if (checkTriggerExists(triggerKey)) {
scheduler.unscheduleJob(TriggerKey.triggerKey(triggerName, groupName));
log.info("delete Tigger, groupName:{}, triggerName:{}", groupName, triggerName);
}
} catch (SchedulerException e) {
log.error(e.getMessage());
}
}
/**
* 通过calendarName 删除 日历排除机制
*
* @param calendarName
*/
public void delCalendar(String calendarName) {
try {
Calendar calendar = scheduler.getCalendar(calendarName);
if (null != calendar) {
scheduler.deleteCalendar(calendarName);
log.info("delete calendar, calendarName:{}", calendarName);
}
} catch (SchedulerException e) {
log.error(e.getMessage());
}
}
/**
* 验证触发器是否存在
*
* @param triggerKey
* @throws SchedulerException
*/
public boolean checkTriggerExists(TriggerKey triggerKey) throws SchedulerException {
return scheduler.checkExists(triggerKey);
}
/**
* 验证任务是否存在
*
* @param jobKey
* @throws SchedulerException
*/
public boolean checkJobExists(JobKey jobKey) throws SchedulerException {
return scheduler.checkExists(jobKey);
}
/**
* 新增/更新 处理 包含/排除 日历
*
* @param trigger
*/
public void addCalendarName(Trigger trigger) {
try {
String calendarName = trigger.getCalendarName();
if (StringUtils.isNotBlank(calendarName)) {
Calendar calendar = scheduler.getCalendar(calendarName);
Object bean = SpringContextUtil.getBean(calendarName);
BaseCalendar m = (BaseCalendar) bean;
if (null == calendar) {
scheduler.addCalendar(calendarName, m, false, false);
} else {
scheduler.addCalendar(calendarName, m, true, true);
}
}
log.info("触发器[{}] 的 calendarName:{},为空,无特殊日期设置任务执行", trigger.getKey().getName(), calendarName);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 暂停定时任务
*
* @param jobName
* @param jobGroup
*/
public void pauseJob(String jobName, String jobGroup) {
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
try {
if (checkJobExists(jobKey)) {
scheduler.pauseJob(jobKey);
log.info("暂停 job success, triggerKey:{},jobGroup:{}, jobName:{}", jobKey, jobGroup, jobName);
}
} catch (SchedulerException e) {
log.error(e.getMessage());
}
}
/**
* 重新恢复任务定时任务
*
* @param jobName
* @param jobGroup
*/
public void resumeJob(String jobName, String jobGroup) {
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
try {
if (checkJobExists(jobKey)) {
scheduler.resumeJob(jobKey);
log.info("恢复 job success, triggerKey:{},jobGroup:{}, jobName:{}", jobKey, jobGroup, jobName);
}
} catch (SchedulerException e) {
log.error(e.getMessage());
}
}
/**
* 暂停任务的触发器
*
* @param triggerName
* @param triggerGroup
*/
public void pauseTrigger(String triggerName, String triggerGroup, String uid) {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
try {
if (checkTriggerExists(triggerKey)) {
scheduler.pauseTrigger(triggerKey);
log.info("暂停 trigger success, triggerKey:{},triggerName:{}, triggerGroup:{}", triggerKey, triggerName, triggerGroup);
}
if (StringUtils.isNotBlank(uid)) {
Trigger trigger = scheduler.getTrigger(triggerKey);
//写入操作日志
addOperationLog(trigger.getJobKey().getName(), trigger.getJobKey().getGroup(), triggerName, triggerGroup, JSON.toJSONString(trigger), uid, QrtzTaskLogPo.operation_update);
}
} catch (SchedulerException e) {
log.error(e.getMessage());
}
}
/**
* 重新恢复任务的触发器
*
* @param triggerName
* @param triggerGroup
*/
public void resumeTrigger(String triggerName, String triggerGroup, String uid) {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
try {
if (checkTriggerExists(triggerKey)) {
scheduler.resumeTrigger(triggerKey);
log.info("恢复 trigger success, triggerKey:{},triggerName:{}, triggerGroup:{}", triggerKey, triggerName, triggerGroup);
}
if (StringUtils.isNotBlank(uid)) {
Trigger trigger = scheduler.getTrigger(triggerKey);
//写入操作日志
addOperationLog(trigger.getJobKey().getName(), trigger.getJobKey().getGroup(), triggerName, triggerGroup, JSON.toJSONString(trigger), uid, QrtzTaskLogPo.operation_update);
}
} catch (SchedulerException e) {
log.error(e.getMessage());
}
}
/**
* 根据定时任务key 获取定时任务注册的所有触发器
*
* @param jobName
* @param jobGroup
* @return
*/
public List<? extends Trigger> getJobTrigger(String jobName, String jobGroup) throws SchedulerException {
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
return triggers;
}
/**
* 根据触发器key 获取单个触发器
*
* @return
*/
public Trigger getSingleTrigger(String triggerName, String triggerGroup) throws SchedulerException {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
Trigger trigger = scheduler.getTrigger(triggerKey);
return trigger;
}
/**
* 获取调度器下的所有JobKey
*
* @return
*/
public List<JobKey> JobKeys() {
List<JobKey> list = new ArrayList<>();
try {
for (String groupJob : scheduler.getJobGroupNames()) {
Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.<JobKey>groupEquals(groupJob));
list.addAll(jobKeys);
}
} catch (SchedulerException e) {
e.printStackTrace();
}
return list;
}
/**
* 获取调度器下的所有任务列表
*
* @return
*/
public List<TaskInfoDto> jobList() {
List<TaskInfoDto> list = new ArrayList<>();
try {
for (String groupJob : scheduler.getJobGroupNames()) {
for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.<JobKey>groupEquals(groupJob))) {
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
for (Trigger trigger : triggers) {
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
TaskInfoDto info = conver(jobDetail, trigger);
list.add(info);
}
}
}
} catch (SchedulerException e) {
e.printStackTrace();
}
return list;
}
public TaskInfoDto conver(JobDetail jobDetail, Trigger trigger) throws SchedulerException {
Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
JobKey jobKey = jobDetail.getKey();
String cronExpression = "", createTime = "";
Date endTime = null;
Date startTime = null;
TaskInfoDto info = new TaskInfoDto();
//简单触发器
if (trigger instanceof SimpleTrigger) {
SimpleTrigger simpleTrigger = (SimpleTrigger) trigger;
endTime = simpleTrigger.getEndTime();
startTime = simpleTrigger.getStartTime();
int repeatCount = simpleTrigger.getRepeatCount();
long repeatInterval = simpleTrigger.getRepeatInterval();
info.setType(QrtzTriggerDefaultPo.tigger_simple);
info.setRepeatCount(repeatCount);
info.setRepeatInterval(repeatInterval);
}
//cron表达式触发器
if (trigger instanceof CronTrigger) {
CronTrigger cronTrigger = (CronTrigger) trigger;
cronExpression = cronTrigger.getCronExpression();
endTime = cronTrigger.getEndTime();
startTime = cronTrigger.getStartTime();
info.setType(QrtzTriggerDefaultPo.tigger_cron);
info.setCronExpression(cronExpression);
}
//日历触发器
if (trigger instanceof CalendarIntervalTrigger) {
CalendarIntervalTrigger calendarTrigger = (CalendarIntervalTrigger) trigger;
int repeatInterval = calendarTrigger.getRepeatInterval();
String repeatIntervalUnit = calendarTrigger.getRepeatIntervalUnit().toString();
endTime = calendarTrigger.getEndTime();
startTime = calendarTrigger.getStartTime();
info.setInterval(repeatInterval);
info.setRepeatIntervalUnit(repeatIntervalUnit);
info.setType(QrtzTriggerDefaultPo.tigger_calendar);
info.setCronExpression(cronExpression);
}
//日期触发器
if (trigger instanceof DailyTimeIntervalTrigger) {
DailyTimeIntervalTrigger dtTrigger = (DailyTimeIntervalTrigger) trigger;
endTime = dtTrigger.getEndTime();
startTime = dtTrigger.getStartTime();
int repeatCount = dtTrigger.getRepeatCount();
Set<Integer> daysOfWeek = dtTrigger.getDaysOfWeek();
int interval = dtTrigger.getRepeatInterval();
String repeatIntervalUnit = dtTrigger.getRepeatIntervalUnit().toString();
TimeOfDay startTimeOfDay = dtTrigger.getStartTimeOfDay();
TimeOfDay endTimeOfDay = dtTrigger.getEndTimeOfDay();
if (null != startTimeOfDay) {
info.setStartTimeOfDay(startTimeOfDay.getHour() + ":" + startTimeOfDay.getMinute() + ":" + startTimeOfDay.getSecond());
}
if (null != endTimeOfDay) {
info.setEndTimeOfDay(endTimeOfDay.getHour() + ":" + endTimeOfDay.getMinute() + ":" + endTimeOfDay.getSecond());
}
info.setInterval(interval);
info.setRepeatIntervalUnit(repeatIntervalUnit);
info.setRepeatCount(repeatCount);
info.setDaysOfWeek(daysOfWeek);
info.setType(QrtzTriggerDefaultPo.tigger_daily);
info.setCronExpression(cronExpression);
}
info.setJobName(jobKey.getName());
info.setJobGroup(jobKey.getGroup());
info.setTriggerName(trigger.getKey().getName());
info.setTriggerGroup(trigger.getKey().getGroup());
info.setJobDescription(jobDetail.getDescription());
info.setJobStatus(triggerState.name());
info.setEndTime(endTime);
info.setStartTime(startTime);
return info;
}
public TaskInfoDto jobInfo(JobInfoQueryDto query) {
String jobname = query.getJobName(),
jobgroup = query.getJobGroup(),
tigname = query.getTriggerName(),
tiggroup = query.getTriggerGroup();
JobKey jobKey = JobKey.jobKey(jobname, jobgroup);
try {
TriggerKey triggerKey = TriggerKey.triggerKey(tigname, tiggroup);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
Trigger trigger = scheduler.getTrigger(triggerKey);
TaskInfoDto info = conver(jobDetail, trigger);
return info;
} catch (SchedulerException e) {
e.printStackTrace();
}
return null;
}
/**
* 运维人员后台修改任务信息
*
* @return
*/
public void edit(TaskInfoDto info) {
String jobName = info.getJobName(),
jobGroup = info.getJobGroup(),
cronExpression = info.getCronExpression(),
jobDescription = info.getJobDescription(),
triggerName = info.getTriggerName(),
triggerGroup = info.getTriggerGroup();
Integer type = info.getType();
boolean isDef = taskInitService.isDefault(jobName, jobGroup, triggerName, triggerGroup);
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
Trigger trigger = scheduler.getTrigger(triggerKey);
if (!isDef) {
//如果没有默认值,将信息更新到默认值表中,作为 还原默认值数据
QrtzTriggerDefaultPo qd = new QrtzTriggerDefaultPo();
qd.setSchedname(scheduler.getSchedulerName());
qd.setJobname(jobName);
qd.setJobgroup(jobGroup);
qd.setTriggername(triggerName);
qd.setTriggergroup(triggerGroup);
qd.setTriggerdata(JSON.toJSONString(trigger));
qd.setTriggertype(type);
qd.setCreatetime(new Date());
qrtzTriggerDefaultDao.insertSelective(qd);
}
if (!checkJobExists(jobKey)) {
log.info("edit job fail, job is not exist, jobGroup:{}, jobName:{}", jobGroup, jobName);
}
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
HashSet<Trigger> triggerSet = new HashSet<>();
if (trigger instanceof CronTrigger) {
CronTriggerImpl cronTrigger = (CronTriggerImpl) trigger;
//更改表达式
cronTrigger.setCronExpression(cronExpression);
jobDetail.getJobBuilder().withDescription(jobDescription);
triggerSet.add(cronTrigger);
}
if (trigger instanceof SimpleTrigger) {
SimpleTriggerImpl simpleTrigger = (SimpleTriggerImpl) trigger;
simpleTrigger.setRepeatInterval(info.getRepeatInterval());
if (info.getRepeatCount() != 0) {
simpleTrigger.setRepeatCount(info.getRepeatCount());
}
triggerSet.add(simpleTrigger);
}
if (trigger instanceof CalendarIntervalTrigger) {
CalendarIntervalTriggerImpl calendarTrigger = (CalendarIntervalTriggerImpl) trigger;
calendarTrigger.setRepeatInterval(info.getInterval());
calendarTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.valueOf(info.getRepeatIntervalUnit()));
triggerSet.add(calendarTrigger);
}
if (trigger instanceof DailyTimeIntervalTrigger) {
DailyTimeIntervalTriggerImpl dailyTrigger = (DailyTimeIntervalTriggerImpl) trigger;
dailyTrigger.setDaysOfWeek(info.getDaysOfWeek());
dailyTrigger.setRepeatInterval(info.getInterval());
dailyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.valueOf(info.getRepeatIntervalUnit()));
if (info.getRepeatCount() != 0) {
dailyTrigger.setRepeatCount(info.getRepeatCount());
}
triggerSet.add(dailyTrigger);
}
scheduler.scheduleJob(jobDetail, triggerSet, true);
if (StringUtils.isNotBlank(info.getIdmuid())) {
//写入操作日志
addOperationLog(jobName, jobGroup, triggerName, triggerGroup, JSON.toJSONString(trigger), info.getIdmuid(), QrtzTaskLogPo.operation_update);
}
} catch (SchedulerException e) {
e.printStackTrace();
log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
} catch (ParseException e) {
e.printStackTrace();
log.error("更改触发器执行表达式错误,exception:{}", e.getMessage());
}
}
/**
* 根据job名 组 当前立即执行某一任务
*
* @param name
* @param group
*/
public void runTaskImmediately(String name, String group) {
try {
JobKey jobKey = JobKey.jobKey(name, group);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (null == jobDetail) {
throw new SchedulerException("任务未加入调度器中");
}
scheduler.triggerJob(JobKey.jobKey(name, group));
} catch (SchedulerException e) {
e.printStackTrace();
log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
}
}
/**
* 恢复任务触发器默认值
*
* @param rd
*/
public void restoreDefault(RestoreDefaultDto rd) {
String jobname = rd.getJobName(),
jobgroup = rd.getJobGroup(),
tigname = rd.getTriggerName(),
tiggroup = rd.getTriggerGroup();
try {
QrtzTriggerDefaultPo qrtzTriggerDefaultPo = new QrtzTriggerDefaultPo();
qrtzTriggerDefaultPo.setJobname(jobname);
qrtzTriggerDefaultPo.setJobgroup(jobgroup);
qrtzTriggerDefaultPo.setTriggername(tigname);
qrtzTriggerDefaultPo.setTriggergroup(tiggroup);
QrtzTriggerDefaultPo qd = qrtzTriggerDefaultDao.selectOne(qrtzTriggerDefaultPo);
String triggerJson = qd.getTriggerdata();
JSONObject jsonObject = JSON.parseObject(triggerJson);
JobKey jobKey = JobKey.jobKey(jobname, jobgroup);
TriggerKey triggerKey = TriggerKey.triggerKey(tigname, tiggroup);
Trigger trigger = scheduler.getTrigger(triggerKey);
if (trigger instanceof SimpleTrigger) {
SimpleTriggerImpl simple = (SimpleTriggerImpl) trigger;
String repeatCount = jsonObject.getString("repeatCount");
String repeatInterval = jsonObject.getString("repeatInterval");
if (StringUtils.isNotBlank(repeatCount)) {
simple.setRepeatCount(Integer.valueOf(repeatCount));
}
simple.setRepeatInterval(Integer.valueOf(repeatInterval));
}
if (trigger instanceof CronTrigger) {
CronTriggerImpl cron = (CronTriggerImpl) trigger;
String cronExpression = jsonObject.getString("cronExpression");
//更改表达式
cron.setCronExpression(cronExpression);
}
if (trigger instanceof CalendarIntervalTrigger) {
CalendarIntervalTriggerImpl calendar = (CalendarIntervalTriggerImpl) trigger;
String repeatInterval = jsonObject.getString("repeatInterval");
String repeatIntervalUnit = jsonObject.getString("repeatIntervalUnit");
calendar.setRepeatInterval(Integer.valueOf(repeatInterval));
calendar.setRepeatIntervalUnit(DateBuilder.IntervalUnit.valueOf(repeatIntervalUnit));
}
if (trigger instanceof DailyTimeIntervalTrigger) {
DailyTimeIntervalTriggerImpl daily = (DailyTimeIntervalTriggerImpl) trigger;
String repeatCount = jsonObject.getString("repeatCount");
String repeatInterval = jsonObject.getString("repeatInterval");
String repeatIntervalUnit = jsonObject.getString("repeatIntervalUnit");
String daysOfWeek = jsonObject.getString("daysOfWeek");
List<Integer> list = JSON.parseArray(daysOfWeek, Integer.class);
Set<Integer> set = new HashSet<>(list);
daily.setRepeatCount(Integer.valueOf(repeatCount));
daily.setRepeatInterval(Integer.valueOf(repeatInterval));
daily.setRepeatIntervalUnit(DateBuilder.IntervalUnit.valueOf(repeatIntervalUnit));
daily.setDaysOfWeek(set);
}
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
updateJob(jobDetail, trigger);
if (StringUtils.isNotBlank(rd.getUid())) {
//写入操作日志
addOperationLog(jobname, jobgroup, tigname, tiggroup, JSON.toJSONString(trigger), rd.getUid(), QrtzTaskLogPo.operation_update);
}
} catch (SchedulerException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
public TaskInfoDto jobDefault(RestoreDefaultDto rd) {
String jobname = rd.getJobName(),
jobgroup = rd.getJobGroup(),
tigname = rd.getTriggerName(),
tiggroup = rd.getTriggerGroup();
String schedulername = SpringContextUtil.getApplicationContext().getEnvironment().getProperty("spring.application.name");
QrtzTriggerDefaultPo qrtzTriggerDefaultPo = new QrtzTriggerDefaultPo();
qrtzTriggerDefaultPo.setSchedname(schedulername);
qrtzTriggerDefaultPo.setJobname(jobname);
qrtzTriggerDefaultPo.setJobgroup(jobgroup);
qrtzTriggerDefaultPo.setTriggername(tigname);
qrtzTriggerDefaultPo.setTriggergroup(tiggroup);
QrtzTriggerDefaultPo qd = qrtzTriggerDefaultDao.selectOne(qrtzTriggerDefaultPo);
if (ObjectUtils.isEmpty(qd)) {
return null;
}
TaskInfoDto taskInfo = new TaskInfoDto();
taskInfo.setJobName(jobname);
taskInfo.setJobGroup(jobgroup);
taskInfo.setTriggerName(tigname);
taskInfo.setTriggerGroup(tiggroup);
JSONObject jsonObject = JSON.parseObject(qd.getTriggerdata());
if (qd.getTriggertype().equals(QrtzTriggerDefaultPo.tigger_simple)) {
String repeatCount = jsonObject.getString("repeatCount");
String repeatInterval = jsonObject.getString("repeatInterval");
taskInfo.setRepeatCount(Integer.valueOf(repeatCount));
taskInfo.setRepeatInterval(Integer.valueOf(repeatInterval));
taskInfo.setType(QrtzTriggerDefaultPo.tigger_simple);
}
if (qd.getTriggertype().equals(QrtzTriggerDefaultPo.tigger_cron)) {
String cronExpression = jsonObject.getString("cronExpression");
taskInfo.setCronExpression(cronExpression);
taskInfo.setType(QrtzTriggerDefaultPo.tigger_cron);
}
if (qd.getTriggertype().equals(QrtzTriggerDefaultPo.tigger_calendar)) {
String repeatInterval = jsonObject.getString("repeatInterval");
String repeatIntervalUnit = jsonObject.getString("repeatIntervalUnit");
taskInfo.setInterval(Integer.valueOf(repeatInterval));
taskInfo.setRepeatIntervalUnit(repeatIntervalUnit);
taskInfo.setType(QrtzTriggerDefaultPo.tigger_cron);
}
if (qd.getTriggertype().equals(QrtzTriggerDefaultPo.tigger_daily)) {
String repeatCount = jsonObject.getString("repeatCount");
String repeatInterval = jsonObject.getString("repeatInterval");
String repeatIntervalUnit = jsonObject.getString("repeatIntervalUnit");
String daysOfWeek = jsonObject.getString("daysOfWeek");
List<Integer> list = JSON.parseArray(daysOfWeek, Integer.class);
Set<Integer> set = new HashSet<>(list);
taskInfo.setRepeatCount(Integer.valueOf(repeatCount));
taskInfo.setInterval(Integer.valueOf(repeatInterval));
taskInfo.setRepeatIntervalUnit(repeatIntervalUnit);
taskInfo.setType(QrtzTriggerDefaultPo.tigger_cron);
taskInfo.setDaysOfWeek(set);
}
return taskInfo;
}
public Pager<RunLogDto> getRunLog(RunLogPageQueryDto runLogPageQueryDto) {
Pager<QrtzTaskRunLogPo> runLog = qrtzTaskRunLogService.getRunLog(runLogPageQueryDto);
Pager<RunLogDto> runLogVoPager = PagerUtils.cast(runLog, RunLogDto.class);
return runLogVoPager;
}
/**
* 写入运维操作日志
*
* @param jobname
* @param jobgroup
* @param triggername
* @param triggergroup
* @param triggerdata
* @param uid
* @param type
*/
public void addOperationLog(String jobname, String jobgroup, String triggername, String triggergroup, String triggerdata, String uid, String type) {
try {
QrtzTaskLogPo qrtzTaskLogPo = new QrtzTaskLogPo();
qrtzTaskLogPo.setSchedname(scheduler.getSchedulerName());
qrtzTaskLogPo.setJobname(jobname);
qrtzTaskLogPo.setJobgroup(jobgroup);
qrtzTaskLogPo.setTriggername(triggername);
qrtzTaskLogPo.setTriggergroup(triggergroup);
qrtzTaskLogPo.setTriggerdata(triggerdata);
qrtzTaskLogPo.setCreatetime(new Date());
qrtzTaskLogPo.setCreateuser(uid);
qrtzTaskLogPo.setOptype(type);
qrtzTaskLogService.addLog(qrtzTaskLogPo);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 获取最近指定次数的执行时间
* @param cronExpression cron表达式
* @param times 次数
* @param dateFormat 返回的时间格式
* @return java.util.List<java.lang.String>
* @author wuzm
* @date 2020/11/2
*/
public List<String> getNextTimes(String cronExpression, int times, String dateFormat) throws ParseException {
List<String> dateList = new ArrayList<>();
if(times > 0){
CronExpression cron = new CronExpression(cronExpression);
Date lastRun = new Date();
for (int i = 0; i < times; i++) {
lastRun = cron.getNextValidTimeAfter(lastRun);
dateList.add(DateUtils.parseDateToString(lastRun, dateFormat));
};
}
return dateList;
}
}定时任务线程池
java
import org.quartz.SchedulerConfigException;
import org.quartz.spi.ThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
/**
* <br>
*
* @author luos
* @date 2020/10/14
*/
@Component
public class TaskPool implements ThreadPool {
private Logger logger = LoggerFactory.getLogger(TaskPool.class);
ExecutorService executorService;
public void setThreadCount(int count) {
}
@Override
public boolean runInThread(Runnable runnable) {
Assert.state(this.executorService != null, "No TaskExecutor available");
try {
this.executorService.execute(runnable);
return true;
} catch (RejectedExecutionException ex) {
logger.error("Task has been rejected by TaskExecutor", ex);
return false;
}
}
@Override
public int blockForAvailableThreads() {
return 1;
}
@Override
public void initialize() throws SchedulerConfigException {
this.executorService = Executors.newCachedThreadPool();
if (this.executorService == null) {
throw new SchedulerConfigException("No local Executor found for configuration - " +
"'taskExecutor' property must be set on SchedulerFactoryBean");
}
}
@Override
public void shutdown(boolean waitForJobsToComplete) {
executorService.shutdownNow();
}
@Override
public int getPoolSize() {
return -1;
}
@Override
public void setInstanceId(String schedInstId) {
}
@Override
public void setInstanceName(String schedName) {
}
}