任务相关信息:springboot-quartz普通任务与可传参任务
一、任务实体类
package cloud.app.prod.home.quartz; import java.io.Serializable; import java.util.Date; /** * Author : YongBo Xie </br> * File Name: ScheduleJob.java 任务job实体类 </br> * Created Date: 2018年4月3日 上午11:33:47 </br> * Modified Date: 2018年4月3日 上午11:33:47 </br> * Version: 1.0 </br> */ public class ScheduleJobEntity implements Serializable { private static final long serialVersionUID = 6009097439379146309L; /** 任务ID */ private String jobId; /** 任务名称 */ private String jobName; /** 任务分组 */ private String jobGroup; /** 任务运行时间表达式 */ private String cronExpression; /** 任务类(必须是Spring中定义的Bean) */ private String targetObject; /** 任务方法 */ private String targetMethod; /** 是否并发 */ private boolean concurrent; /** 触发器开始执行任务时间 */ private Date startDate; /** 触发器结束执行任务时间 */ private Date endDate; public String getJobId() { return jobId; } public void setJobId(String jobId) { this.jobId = jobId; } public String getJobName() { return jobName; } public void setJobName(String jobName) { this.jobName = jobName; } public String getJobGroup() { return jobGroup; } public void setJobGroup(String jobGroup) { this.jobGroup = jobGroup; } public String getCronExpression() { return cronExpression; } public void setCronExpression(String cronExpression) { this.cronExpression = cronExpression; } public String getTargetObject() { return targetObject; } public void setTargetObject(String targetObject) { this.targetObject = targetObject; } public String getTargetMethod() { return targetMethod; } public void setTargetMethod(String targetMethod) { this.targetMethod = targetMethod; } public boolean isConcurrent() { return concurrent; } public void setConcurrent(boolean concurrent) { this.concurrent = concurrent; } public Date getStartDate() { return startDate; } public void setStartDate(Date startDate) { this.startDate = startDate; } public Date getEndDate() { return endDate; } public void setEndDate(Date endDate) { this.endDate = endDate; } }
二、Spring应用上下文环境
package cloud.app.prod.home.quartz; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * Author : YongBo Xie </br> * File Name: SpringContextUtil.java </br> * Created Date: 2018年4月3日 上午11:27:55 </br> * Modified Date: 2018年4月3日 上午11:27:55 </br> * Version: 1.0 </br> */ @Component public class SpringContextUtil implements ApplicationContextAware { // Spring应用上下文环境 private static ApplicationContext applicationContext; /** * 实现ApplicationContextAware接口的回调方法,设置上下文环境 */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringContextUtil.applicationContext = applicationContext; } public static ApplicationContext getApplicationContext() { return applicationContext; } /** * 根据指定bean名称,获取对应的实例对象 * @param name bean的名称 * @return * @throws BeansException */ public static Object getBean(String name) throws BeansException { if (applicationContext == null) { throw new RuntimeException("spring 上下文对象未初始化,无法完成bean的查找!"); } return applicationContext.getBean(name); } /** * 根据指定Bean类型,获取对应的实例对象 * @param requiredType bean的class类型 * @return * @throws BeansException */ public static <T> T getBean(Class<T> requiredType) throws BeansException { if (applicationContext == null) { throw new RuntimeException("spring 上下文对象未初始化,无法完成bean的查找!"); } return applicationContext.getBean(requiredType); } }
三、自定义MyJobFactory类,实现自动注入
package cloud.app.prod.home.quartz; 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 : YongBo Xie </br> * File Name: MyJobFactory.java </br> * Created Date: 2018年4月2日 下午3:27:30 </br> * Modified Date: 2018年4月2日 下午3:27:30 </br> * Version: 1.0 </br> */ @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); return jobInstance; } }
四、配置SchedulerFactoryBean
package cloud.app.prod.home.quartz; import java.io.IOException; import java.util.Properties; 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.annotation.EnableScheduling; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import cloud.app.prod.home.quartz.MyJobFactory; /** * Author : YongBo Xie </br> * File Name: QuartzConfigration.java </br> * Created Date: 2018年3月31日 下午3:42:04 </br> * Modified Date: 2018年3月31日 下午3:42:04 </br> * Version: 1.0 </br> */ @Configuration @EnableScheduling public class QuartzConfigration { @Autowired private MyJobFactory myJobFactory; @Bean public SchedulerFactoryBean schedulerFactoryBean() throws IOException { SchedulerFactoryBean factory = new SchedulerFactoryBean(); // 用于quartz集群,QuartzScheduler 启动时更新己存在的Job factory.setOverwriteExistingJobs(true); // 延时启动,应用启动1秒后 // factory.setStartupDelay(1); // 加载quartz数据源配置 // factory.setQuartzProperties(quartzProperties()); // 自定义Job Factory,用于Spring注入 factory.setJobFactory(myJobFactory); return factory; } /** * 加载quartz数据源配置 * * @return * @throws IOException */ @Bean public Properties quartzProperties() throws IOException { PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties")); propertiesFactoryBean.afterPropertiesSet(); return propertiesFactoryBean.getObject(); } }
五、定时任务公共操作类
package cloud.app.prod.home.quartz; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import org.quartz.CronScheduleBuilder; import org.quartz.CronTrigger; import org.quartz.Job; import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.TriggerBuilder; import org.quartz.TriggerKey; import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean; import cloud.app.prod.home.common.FailException; import cloud.app.prod.home.utils.DSHUtils; /** * Author : YongBo Xie </br> * File Name: QuartzUtil.java </br> * Created Date: 2018年4月3日 上午10:58:32 </br> * Modified Date: 2018年4月3日 上午10:58:32 </br> * Version: 1.0 </br> */ public class QuartzUtil { private static Logger logger = Logger.getLogger(QuartzUtil.class); public static List<String> jobNames = new ArrayList<String>(); public static String getScheduleJobName(String jobName) { if (jobNames.contains(jobName)) { return jobName; } return null; } /** * 创建一个定时任务,并做安排(用于继承job类的执行方法) * * @param scheduler * @param scheduleJob * @param paramsMap * @param jobClass * @throws FailException */ public static void createSheduler(Scheduler scheduler, ScheduleJobEntity scheduleJob, Map<String, Object> paramsMap, Class<? extends Job> jobClass) throws FailException { try { logger.info("----- scheduling job --------"); // 创建一项作业 JobDetail jobDetail = JobBuilder.newJob(jobClass) .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()) .build(); // 设置参数 for (Map.Entry<String, Object> entry : paramsMap.entrySet()) { jobDetail.getJobDataMap().put(entry.getKey(), entry.getValue()); } // 作业的执行时间(当前时间的下一分钟) // Date runTime = DateBuilder.evenMinuteDate(new Date()); // 创建一个触发器 CronTrigger trigger = null; if (null != scheduleJob.getStartDate() && null != scheduleJob.getEndDate()) { trigger = (CronTrigger) TriggerBuilder.newTrigger() .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()) .startAt(scheduleJob.getStartDate()) // 该触发器开始执行作业时间 .endAt(scheduleJob.getEndDate()) // 该触发器结束作业时间 .withSchedule(CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())) // 具体执行时间 .build(); } else if (null != scheduleJob.getStartDate() && null == scheduleJob.getEndDate()) { trigger = (CronTrigger) TriggerBuilder.newTrigger() .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()) .startAt(scheduleJob.getStartDate()) // 该触发器开始执行作业时间 .withSchedule(CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())) // 具体执行时间 .build(); } else if (null == scheduleJob.getStartDate() && null != scheduleJob.getEndDate()) { trigger = (CronTrigger) TriggerBuilder.newTrigger() .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()) .endAt(scheduleJob.getEndDate()) // 该触发器结束作业时间 .withSchedule(CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())) // 具体执行时间 .build(); } else { trigger = (CronTrigger) TriggerBuilder.newTrigger() .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()) .withSchedule(CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())) // 具体执行时间 .build(); } // 告诉调度器使用该触发器来安排作业 scheduler.scheduleJob(jobDetail, trigger); // 启动调度器 scheduler.start(); logger.info("------ started scheduler -------"); logger.info("------ waiting 2 minutes ------"); Thread.sleep(2 * 60 * 1000); // logger.info("------- shutting down ------"); // // 关闭调度器 // scheduler.shutdown(true); // logger.info("------- shutdown complete -------"); } catch (Exception e) { logger.error(DSHUtils.formatException(e)); throw new FailException(e.getMessage()); } } /** * 创建一个定时任务,并做安排(用于自定义执行方法) * * @param scheduler * @param scheduleJob * @param paramsMap * @throws FailException */ public static void createSheduler(Scheduler scheduler, ScheduleJobEntity scheduleJob, Map<String, Object> paramsMap) throws FailException { try { // 新建一个基于Spring的管理Job类 MethodInvokingJobDetailFactoryBean methodInvJobDetailFB = new MethodInvokingJobDetailFactoryBean(); // 设置Job组名称 methodInvJobDetailFB.setGroup(scheduleJob.getJobGroup()); // 设置Job名称 methodInvJobDetailFB.setName(scheduleJob.getJobName()); // 设置任务类 methodInvJobDetailFB.setTargetObject(SpringContextUtil.getApplicationContext().getBean(scheduleJob.getTargetObject())); // 设置任务方法 methodInvJobDetailFB.setTargetMethod(scheduleJob.getTargetMethod()); // 将管理Job类提交到计划管理类 methodInvJobDetailFB.afterPropertiesSet(); // 并发设置 methodInvJobDetailFB.setConcurrent(scheduleJob.isConcurrent()); JobDetail jobDetail = methodInvJobDetailFB.getObject();// 动态 // 设置参数 for (Map.Entry<String, Object> entry : paramsMap.entrySet()) { jobDetail.getJobDataMap().put(entry.getKey(), entry.getValue()); } // jobName存入到队列 每隔一段时间就会扫描所以需要时检测 if (!QuartzUtil.jobNames.contains(scheduleJob.getJobName())) { QuartzUtil.jobNames.add(scheduleJob.getJobName()); } // 表达式调度构建器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()); // 按新的cronExpression表达式构建一个新的trigger CronTrigger trigger = null; if (null != scheduleJob.getStartDate() && null != scheduleJob.getEndDate()) { trigger = (CronTrigger) TriggerBuilder.newTrigger() .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()) .startAt(scheduleJob.getStartDate()) // 该触发器开始执行作业时间 .endAt(scheduleJob.getEndDate()) // 该触发器结束作业时间 .withSchedule(scheduleBuilder) // 具体执行时间 .build(); } else if (null != scheduleJob.getStartDate() && null == scheduleJob.getEndDate()) { trigger = (CronTrigger) TriggerBuilder.newTrigger() .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()) .startAt(scheduleJob.getStartDate()) // 该触发器开始执行作业时间 .withSchedule(scheduleBuilder) // 具体执行时间 .build(); } else if (null == scheduleJob.getStartDate() && null != scheduleJob.getEndDate()) { trigger = (CronTrigger) TriggerBuilder.newTrigger() .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()) .endAt(scheduleJob.getEndDate()) // 该触发器结束作业时间 .withSchedule(scheduleBuilder) // 具体执行时间 .build(); } else { trigger = (CronTrigger) TriggerBuilder.newTrigger() .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()) .withSchedule(scheduleBuilder) // 具体执行时间 .build(); } // 暂时停止 任务都安排完之后统一启动 解决耗时任务按照顺序部署后执行紊乱的问题 // scheduler.standby(); // 注入到管理类 scheduler.scheduleJob(jobDetail, trigger); logger.info(scheduleJob.getJobGroup() + "." + scheduleJob.getJobName() + "创建完毕"); } catch (Exception e) { logger.error(DSHUtils.formatException(e)); throw new FailException(e.getMessage()); } } /** * 修改定时任务 * @param scheduler * @param scheduleJob * @param triggerKey * @param trigger * @throws FailException */ public static void updateScheduler(Scheduler scheduler, ScheduleJobEntity scheduleJob, TriggerKey triggerKey, CronTrigger trigger) throws FailException { try { if (!trigger.getCronExpression().equalsIgnoreCase(scheduleJob.getCronExpression())) { // 表达式调度构建器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()); // 按新的cronExpression表达式重新构建trigger trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); // 按新的trigger重新设置job执行 scheduler.rescheduleJob(triggerKey, trigger); logger.info(scheduleJob.getJobGroup() + "." + scheduleJob.getJobName() + " 更新完毕,目前cron表达式为:" + scheduleJob.getCronExpression() + " concurrent: " + scheduleJob.isConcurrent()); } } catch (Exception e) { logger.error(DSHUtils.formatException(e)); throw new FailException(e.getMessage()); } } /** * 删除定时任务 * @param scheduler * @param triggerKey * @param trigger * @throws FailException */ public static void deleteScheduler(Scheduler scheduler, TriggerKey triggerKey, CronTrigger trigger) throws FailException { try { scheduler.pauseTrigger(triggerKey);// 停止触发器 scheduler.unscheduleJob(triggerKey);// 移除触发器 scheduler.deleteJob(trigger.getJobKey());// 删除任务 logger.info(triggerKey.getGroup() + "." + triggerKey.getName() + "删除完毕"); } catch (Exception e) { logger.error(DSHUtils.formatException(e)); throw new FailException(e.getMessage()); } } /** * 暂停定时任务 * @param scheduler * @param trigger * @throws FailException */ public static void pauseScheduler(Scheduler scheduler, CronTrigger trigger) throws FailException { try { scheduler.pauseJob(trigger.getJobKey());// 暂停任务 logger.info(trigger.getJobKey().getGroup() + "." + trigger.getJobKey().getName() + "暂停完毕"); } catch (Exception e) { logger.error(DSHUtils.formatException(e)); throw new FailException(e.getMessage()); } } /** * 恢复定时任务 * @param scheduler * @param trigger * @throws FailException */ public static void resumeScheduler(Scheduler scheduler, CronTrigger trigger) throws FailException { try { scheduler.resumeJob(trigger.getJobKey());// 恢复任务 logger.info(trigger.getJobKey().getGroup() + "." + trigger.getJobKey().getName() + "恢复完毕"); } catch (Exception e) { logger.error(DSHUtils.formatException(e)); throw new FailException(e.getMessage()); } } /** * 立即执行定时任务 * @param scheduler * @param trigger * @throws FailException */ public static void triggerScheduler(Scheduler scheduler, CronTrigger trigger) throws FailException { try { scheduler.triggerJob(trigger.getJobKey());// 立即执行任务 logger.info(trigger.getJobKey().getGroup() + "." + trigger.getJobKey().getName() + "立即执行完毕"); } catch (Exception e) { logger.error(DSHUtils.formatException(e)); throw new FailException(e.getMessage()); } } }
六、具体任务操作类
package cloud.app.prod.home.quartz.mem; import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; import org.quartz.CronTrigger; import org.quartz.DisallowConcurrentExecution; import org.quartz.Scheduler; import org.quartz.TriggerKey; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.stereotype.Component; import cloud.app.prod.home.common.FailException; import cloud.app.prod.home.mem.vo.MarketingActivitiesVO; import cloud.app.prod.home.quartz.QuartzUtil; import cloud.app.prod.home.quartz.ScheduleJobEntity; import cloud.app.prod.home.utils.DSHUtils; /** * Author : YongBo Xie </br> * File Name: ScheduleRefreshDatabase.java </br> * Created Date: 2018年3月31日 下午3:58:08 </br> * Modified Date: 2018年3月31日 下午3:58:08 </br> * Version: 1.0 </br> */ @Component @DisallowConcurrentExecution // 任务同步 public class MarketingActivityScheduleHandle { private static Logger logger = Logger.getLogger(MarketingActivityScheduleHandle.class); @Autowired private SchedulerFactoryBean schedulerFactoryBean; // 公用Scheduler,同一个对象 // public static Scheduler scheduler = (Scheduler) SpringContextUtil.getApplicationContext().getBean("schedulerFactoryBean"); @Scheduled(fixedRate = 5000) // 每隔5s查库 // @Scheduled(cron = "0 0 1 * * ?") public void scheduleRefreshCron() throws FailException { try{ logger.info("----- scheduling job --------"); String searchCron = "*/5 * * * * ?";// 从数据库查询出来的 // 获取一个调度器 // SchedulerFactory factory = new StdSchedulerFactory(); // Scheduler scheduler = factory.getScheduler(); Scheduler scheduler = schedulerFactoryBean.getScheduler(); // 设置参数 MarketingActivitiesVO marketingActivitiesVO = new MarketingActivitiesVO(); marketingActivitiesVO.setId(DSHUtils.generateUUID()); ScheduleJobEntity scheduleJob = new ScheduleJobEntity(); scheduleJob.setJobId(marketingActivitiesVO.getId()); scheduleJob.setJobName("marketingActivity"); scheduleJob.setJobGroup("marketingActivityGroup"); scheduleJob.setCronExpression(searchCron); scheduleJob.setTargetObject("marketingActivityScheduleTask"); scheduleJob.setTargetMethod("executeInternal"); scheduleJob.setConcurrent(true); Map<String, Object> paramsMap = new HashMap<>(); paramsMap.put("marketingActivitiesVO", marketingActivitiesVO); // 获取triggerKey TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup()); // 获取trigger CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); // 不存在,创建一个 if (null == trigger) { // 创建一个触发器 QuartzUtil.createSheduler(scheduler, scheduleJob, paramsMap, MarketingActivityScheduleTask.class); // QuartzUtil.createSheduler(scheduler, scheduleJob, paramsMap); } else {// Trigger已存在,那么更新相应的定时设置 QuartzUtil.updateScheduler(scheduler, scheduleJob, triggerKey, trigger); // 删除 QuartzUtil.deleteScheduler(scheduler, triggerKey, trigger); } }catch(Exception e){ logger.error(DSHUtils.formatException(e)); throw new FailException(e.getMessage()); } } }
七:1)、具体任务执行类(继承Job)
package cloud.app.prod.home.quartz.mem; import org.apache.log4j.Logger; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.quartz.QuartzJobBean; import org.springframework.stereotype.Component; import cloud.app.prod.home.common.FailException; import cloud.app.prod.home.mem.vo.MarketingActivitiesVO; import cloud.app.prod.home.rabbitmq.mem.MarketingActivitieRabbitMqSender; /** * Author : YongBo Xie </br> * File Name: ScheduleTask.java </br> * Created Date: 2018年3月31日 下午3:37:43 </br> * Modified Date: 2018年3月31日 下午3:37:43 </br> * Version: 1.0 </br> */ @Component // 此注解必加 @EnableScheduling // 此注解必加 public class MarketingActivityScheduleTask extends QuartzJobBean { private static Logger logger = Logger.getLogger(MarketingActivityScheduleTask.class); @Autowired private MarketingActivitieRabbitMqSender marketingActivitieRabbitMqSender; @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { logger.info("execute activity"); JobDataMap dataMap = context.getJobDetail().getJobDataMap(); MarketingActivitiesVO marketingActivitiesVO = (MarketingActivitiesVO) dataMap.get("marketingActivitiesVO"); logger.info("marketingActivitiesVO.id: " + marketingActivitiesVO.getId()); try { logger.info("marketingActivitieRabbitMqSender: " + marketingActivitieRabbitMqSender); marketingActivitieRabbitMqSender.sendRabbitmqDirect(marketingActivitiesVO); } catch (FailException e) { e.printStackTrace(); } } }
2)、具体任务执行类(自定义执行方法)
package cloud.app.prod.home.quartz.mem; import org.apache.log4j.Logger; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.stereotype.Component; import cloud.app.prod.home.common.FailException; /** * Author : YongBo Xie </br> * File Name: ScheduleTask.java </br> * Created Date: 2018年3月31日 下午3:37:43 </br> * Modified Date: 2018年3月31日 下午3:37:43 </br> * Version: 1.0 </br> */ @Configuration @Component // 此注解必加 @EnableScheduling // 此注解必加 public class ScheduleTask { private static Logger logger = Logger.getLogger(ScheduleTask.class); public void marketingActivity() throws FailException { logger.info("execute activity"); } }