一、可配置的定时服务先设计数据库表结构
CREATE TABLE `job` (
`id` CHAR(36) NOT NULL,
`name` VARCHAR(36) NOT NULL COMMENT '任务名',
`bean_name` VARCHAR(100) NOT NULL COMMENT 'spring bean name',
`execute_exp` VARCHAR(200) NOT NULL COMMENT '执行的表达式',
`state` INT(11) NOT NULL DEFAULT '1' COMMENT '1有效2无效',
`remark` VARCHAR(100) NULL DEFAULT '1' COMMENT '描述信息',
`create_time` DATETIME NOT NULL,
PRIMARY KEY (`id`)
)
二、定义QuartzManager 管理器 可以使得注入可用
public class QuartzManager {
private static SchedulerFactory sf = null;
private static String Default_JOB_GROUP_NAME = "job_group";
private static String Default_TRIGGER_GROUP_NAME = "job_trigger";
static {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = QuartzManager.class.getClassLoader();
}
// 加载属性文件app.properties
InputStream is = null;
try {
is = classLoader.getResourceAsStream("conf/quartz.properties");
Properties properties = new Properties();
properties.load(is);
is.close();
is = null;
sf = new StdSchedulerFactory(properties);
} catch (Exception e1) {
e1.printStackTrace();
}
}
/**
* 添加任务
*
* @param jobName
* @param triggerName
* @param jobClass
* @param time
* @return
* @throws SchedulerException
* @throws ParseException
*/
public static JobDetail addJob(String jobId, String triggerName, String beanName, Class<? extends Job> jobClass,
String time) throws SchedulerException, ParseException {
Scheduler sched = sf.getScheduler();
JobDetail jobDetail = newJob(jobClass).withIdentity(jobId, Default_JOB_GROUP_NAME).build();// 任务名,任务组,任务执行类
jobDetail.getJobDataMap().put("beanName", beanName);
jobDetail.getJobDataMap().put("jobId", jobId);
CronTrigger trigger = newTrigger().withIdentity(triggerName, Default_TRIGGER_GROUP_NAME)
.withSchedule(cronSchedule(time)).build();
sched.scheduleJob(jobDetail, trigger);
if (!sched.isShutdown()) sched.start();
return jobDetail;
}
public static List<? extends Trigger> getTriggerKeys(JobKey jobKey) throws SchedulerException {
return sf.getScheduler().getTriggersOfJob(jobKey);
}
/**
* 触发一个任务
*
* @param jobKey
* @throws SchedulerException
*/
public static void triggerJob(JobKey jobKey) throws SchedulerException {
sf.getScheduler().triggerJob(jobKey);
}
/**
* 得到一个触发器的任务状态
*
* @param triggerKey
* @return
* @throws SchedulerException
*/
public static TriggerState getTriggerState(TriggerKey triggerKey) throws SchedulerException {
return sf.getScheduler().getTriggerState(triggerKey);
}
/**
* 移除任务
*
* @param jobName
* @param triggerName
* @param jobClass
* @param time
* @return
* @throws SchedulerException
* @throws ParseException
*/
public static void removeJob(JobKey jobKey) throws SchedulerException {
Scheduler sched = sf.getScheduler();
sched.pauseJob(jobKey);
sched.deleteJob(jobKey);
}
public static void clearAll() throws SchedulerException {
Scheduler sched = sf.getScheduler();
sched.clear();
sched.shutdown();
}
}
三、定义接口类
public interface IQuartzBaseJobService {
public boolean execute(Job job);
}
四、每个新的beanName 实现 IQuartzBaseJobService走自己的逻辑
五、考虑到每个接口只实现,自己的业务不能加日志等信息,需要定义一个类来完成这事
public class QuartzSpringBeanJob implements org.quartz.Job {
private final Logger logger = LoggerFactory.getLogger(QuartzSpringBeanJob.class);
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDetail job = context.getJobDetail();
String jobId = job.getJobDataMap().getString("jobId");
String jobBeanName = job.getJobDataMap().getString("beanName");
if (StringUtils.isEmpty(jobId) || StringUtils.isEmpty(jobBeanName)) {
return;
}
boolean success = true;
String message = "";
// 检查当前job是否可以执行
IJobService jobService = SpringContextHolder.getBean("jobService");
Job jobBean = jobService.findUnique(jobId);
if (jobBean == null || jobBean.getState() != BooleanEnum.True.getValue()) {
try {
QuartzManager.removeJob(job.getKey());
} catch (SchedulerException e) {
logger.error(e.getMessage(), e);
e.printStackTrace();
}
return;
}
IJobLogService jobLogService = SpringContextHolder.getBean("jobLogService");
// 查询上一次是否已经执行成功
boolean existsDoing = jobLogService.existsUnComplete(jobId);
// 生成job日志
JobLog jobLog = new JobLog();
jobLog.setId(GuidKeyGenerator.getUUIDKey());
jobLog.setJobId(jobId);
jobLog.setStartTime(new Date());
if(!existsDoing){
jobLog.setState(JobLogStateEnum.Doing.getValue());
} else {
jobLog.setState(JobLogStateEnum.UnStart.getValue());
jobLog.setMessage("上次未执行结束!本次不再执行!");
}
jobLogService.create(jobLog);
if(existsDoing){// 还有没有执行完的,就不再执行了
return ;
}
try {
IQuartzBaseJobService quartzBaseJobService = SpringContextHolder.getBean(jobBeanName);//为自己bean
if (quartzBaseJobService != null) {
quartzBaseJobService.execute(jobBean);
}
} catch (Exception e) {
success = false;
message = e.getMessage();
logger.error(e.getMessage(), e);
}
// 更新日志状态
JobLog newJobLog = new JobLog();
newJobLog.setId(jobLog.getId());
newJobLog.setState(success ? JobLogStateEnum.Success.getValue() : JobLogStateEnum.Error.getValue());
newJobLog.setEndTime(new Date());
newJobLog.setMessage(message);
jobLogService.update(newJobLog, jobLog);
}
六、一般spring 启动就想执行监听
@Service
public class JobTaskService implements IJobTaskService, Initalizer {
private final Logger logger = LoggerFactory.getLogger(JobTaskService.class);
private final static Map<String, JobDetail> jobDetailMap = new HashMap<String, JobDetail>();
@Autowired
private IJobService jobService;
@Autowired
private IJobLogService jobLogService;
@Override
public void initalize() {
jobLogService.clearDoing();
startAll();
}
private void startAll() {
List<Job> jobs = jobService.findValid();
if (jobs == null) return;
for (Job job : jobs) {
try {
JobDetail jobDetail = QuartzManager.addJob(job.getId(), "trigger-" + job.getId(), job.getBeanName(),
QuartzSpringBeanJob.class, job.getExecuteExp());
jobDetailMap.put(job.getId(), jobDetail);
} catch (Exception e) {
e.printStackTrace();
logger.error("addJobError:jobId:" + job.getId() + e.getMessage(), e);
}
}
}
}
七、考虑到新增修改删除,所以我把我用的方法列
public static void removeJob(String jobName) throws SchedulerException{
try {
Scheduler sched = sf.getScheduler();
sched.pauseTrigger(new TriggerKey(jobName, Default_TRIGGER_GROUP_NAME));// 停止触发器
sched.unscheduleJob(new TriggerKey(jobName, Default_TRIGGER_GROUP_NAME));// 移除触发器
sched.deleteJob(new JobKey(jobName, Default_JOB_GROUP_NAME));// 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void modifyJobTime(String triggerName,
String triggerGroupName, String time) {
try {
Scheduler sched = sf.getScheduler();
TriggerKey triggerKey = new TriggerKey(triggerName,Default_TRIGGER_GROUP_NAME);
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
CronScheduleBuilder scheduleBuilder = cronSchedule(time);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(time)) {
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(scheduleBuilder).build();
//按新的trigger重新设置job执行
sched.rescheduleJob(triggerKey, trigger);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void clearAll() throws SchedulerException {
Scheduler sched = sf.getScheduler();
sched.clear();
sched.shutdown();
}
<pre name="code" class="java"> /**
* 触发一个任务
*
* @param jobKey
* @throws SchedulerException
*/
public static void triggerJob(JobKey jobKey) throws SchedulerException {
sf.getScheduler().triggerJob(jobKey);
}
八、总结一下
Trigger 就是个触发器 jobDetail 就是那个类要作这件事情
scheduler 一个工厂对象返回,作什么事几点作就可以了。
scheduler.start();
成了