一、前言
在使用基础版配置批量任务跑批后,逐渐发现有两个弊端。第一,每次变动跑批的时间策略或停止某个批西欧需要改配置文件,重启服务;第二,项目后期跑批任务越来越多,跑批时间点又比较集中,因此需要视情况微调跑批策略 ,又面临改配置重启的问题。有鉴于此,决定将跑批任务配置参数均配在数据库里,数据库里随便变,代码不变。类似于Drools;
二、具体配置
2.1 配置项
<!-- 线程执行器配置,用于任务注册 -->
<bean id="executor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="queueCapacity" value="500" />
</bean>
<!-- ============= 业务对象============= 将需要添加定时任务调度的类配置到这里 --><bean id="quartzManager" class="com.byhj.batch.process.quartz.QuartzManager">
<property name="scheduler" ref="schedulerBean" />
</bean>
<!-- ============= 调度业务============= -->
<!-- 批量跑批管理 -->
<bean id="batchTaskManagementService" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<!-- 要调用的对象 -->
<property name="targetObject" ref="quartzManager" />
<!-- 要执行的方法名称 -->
<property name="targetMethod" value="reScheduleJob" />
<!-- 如果前一个任务还没有结束第二个任务不会启动 false -->
<property name="concurrent" value="false" />
</bean>
<!-- ============= 调度触发器 ============= -->
<bean id="batchTaskManagementTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="batchTaskManagementService" />
<property name="cronExpression" value="0/20 * * * * ?" />
</bean>
<!-- ============= 调度工厂 ============= -->
<bean id="schedulerBean"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean"
lazy-init="false">
<property name="triggers">
<list>
<!-- 批量跑批管理 -->
<ref bean="batchTaskManagementTrigger" />
</list>
</property>
</bean>
2.2 配套方法
package com.byhj.batch.process.quartz;
import java.text.ParseException;
import java.util.List;
import org.apache.log4j.Logger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.quartz.CronTriggerBean;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.byhj.mysql.model.BatchTaskManagementEntity;
import com.byhj.mysql.service.BatchTaskManagementManager;
import com.byhj.mysql.utils.StringUtil;
@Controller
@RequestMapping(value = "QuartzManager")
public class QuartzManager implements BeanFactoryAware {
static Logger log = Logger.getLogger(QuartzManager.class);private Scheduler scheduler;
private static BeanFactory beanFactory = null;
@Autowired
@Qualifier(value = "batchTaskManagementManager")
private BatchTaskManagementManager batchTaskManagementManager;
@SuppressWarnings("unused")
private void reScheduleJob() throws Exception, ParseException {
// 通过查询数据库里计划任务来配置计划任务
List<BatchTaskManagementEntity> quartzList = batchTaskManagementManager.findAllBatchTaskManagement("console"); //从数据库中获取所有的配置信息,根据自己的获取方式来写,此不赘述
//this.getConfigQuartz();
if (quartzList != null && quartzList.size() > 0) {
//1代表批量代偿跑批
for (BatchTaskManagementEntity tbcq1 : quartzList) {
configQuatrz(tbcq1);
}
}
}
public boolean configQuatrz(BatchTaskManagementEntity tbcq) {
boolean result = false;
try {
// 运行时可通过动态注入的scheduler得到trigger
CronTriggerBean trigger = (CronTriggerBean) scheduler.getTrigger(
tbcq.getTriggername(), Scheduler.DEFAULT_GROUP);
// 如果计划任务已存在则调用修改方法
if (trigger != null) {
change(tbcq, trigger);
} else {
// 如果计划任务不存在并且数据库里的任务状态为可用时,则创建计划任务
if (tbcq.getState().equals("1")) {
this.createCronTriggerBean(tbcq);
}
}
result = true;
} catch (Exception e) {
result = false;
e.printStackTrace();
}
return result;
}
public void change(BatchTaskManagementEntity tbcq, CronTriggerBean trigger)
throws Exception {
// 如果任务为可用
if (tbcq.getState().equals("1")) {
// 判断从DB中取得的任务时间和现在的quartz线程中的任务时间是否相等
// 如果相等,则表示用户并没有重新设定数据库中的任务时间,这种情况不需要重新rescheduleJob
if (!trigger.getCronExpression().equalsIgnoreCase(
tbcq.getCronexpression())) {
trigger.setCronExpression(tbcq.getCronexpression());
scheduler.rescheduleJob(tbcq.getTriggername(),
Scheduler.DEFAULT_GROUP, trigger);
log.info(": 更新" + tbcq.getTriggername() + "计划任务,"+"跑批策略修改为:"+tbcq.getCronexpression());
}
} else {
// 不可用
scheduler.pauseTrigger(trigger.getName(), trigger.getGroup());// 停止触发器
scheduler.unscheduleJob(trigger.getName(), trigger.getGroup());// 移除触发器
scheduler.deleteJob(trigger.getJobName(), trigger.getJobGroup());// 删除任务
log.info(": 删除" + tbcq.getTriggername() + "计划任务");
}
}
/**
* 创建/添加计划任务
*
* @param tbcq
* 计划任务配置对象
* @throws Exception
*/
public void createCronTriggerBean(BatchTaskManagementEntity tbcq) throws Exception {
// 新建一个基于Spring的管理Job类
MethodInvokingJobDetailFactoryBean mjdfb = new MethodInvokingJobDetailFactoryBean();
mjdfb.setName(tbcq.getJobdetailname());// 设置Job名称
// 如果定义的任务类为Spring的定义的Bean则调用 getBean方法
if (tbcq.getIsspringbean().equals("1")) {
mjdfb.setTargetObject(beanFactory.getBean(tbcq.getTargetobject()));// 设置任务类
} else {
// 否则直接new对象
mjdfb.setTargetObject(Class.forName(tbcq.getTargetobject())
.newInstance());// 设置任务类
}
mjdfb.setTargetMethod(tbcq.getMethodname());// 设置任务方法
//传入参数
if(!StringUtil.empty(tbcq.getReserved2())){
Object[] args = {tbcq.getReserved2()};
mjdfb.setArguments(args);
}
mjdfb.setConcurrent(tbcq.getConcurrent().equals("0") ? false : true); // 设置是否并发启动任务
mjdfb.afterPropertiesSet();// 将管理Job类提交到计划管理类
// 将Spring的管理Job类转为Quartz管理Job类
JobDetail jobDetail = new JobDetail();
jobDetail = (JobDetail) mjdfb.getObject();
jobDetail.setName(tbcq.getJobdetailname());
scheduler.addJob(jobDetail, true); // 将Job添加到管理类
// 新一个基于Spring的时间类
CronTriggerBean c = new CronTriggerBean();
c.setCronExpression(tbcq.getCronexpression());// 设置时间表达式
c.setName(tbcq.getTriggername());// 设置名称
c.setJobDetail(jobDetail);// 注入Job
c.setJobName(tbcq.getJobdetailname());// 设置Job名称
scheduler.scheduleJob(c);// 注入到管理类
scheduler.rescheduleJob(tbcq.getTriggername(), Scheduler.DEFAULT_GROUP,
c);// 刷新管理类
log.info(": 新建" + tbcq.getTriggername() + "计划任务,跑批策略:"+tbcq.getCronexpression());
}
public Scheduler getScheduler() {
return scheduler;
}
public void setScheduler(Scheduler scheduler) {
this.scheduler = scheduler;
}
public void setBeanFactory(BeanFactory factory) throws BeansException {
this.beanFactory = factory;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
}
三、补充
配置项和配置方法可以不做任何变动加到项目中即可运行实现跑批任务