赞
踩
引用上一篇博客的说法 springboot整合xxl-job ,集群模式下,定时任务会造成很严重的事故,其次普通的任务也无法做到像xxl-job与Quartz 一样,及时启停,修改等;上一篇介绍了xxl-job,这篇搞一下Quartz,老牌分布式定时任务了;
比较详细的Quartz文档
Quartz 并没有给出明确的例子,但是文档详细,且任务的操作简单明了,步骤清晰,本身是可以脱离Spring-boot 单独工作的,而且可以更高度自定义话。需要自己摸搜整合,一般还需要自己维护数据库的表等,为了任务的添加做参数等;
xxl-job 官方提供了springboot以及普通项目集成demo,所以在集成方面,只要理解了它的思想xxl-job集成很快,数据库等都是现有的,导入即可;但是封装较深,尤其分为了服务端与客户端,无形增加了服务数量,且通信之间还有可能有通信信息丢失情况等;
例如: 每天晚上12点执行一次清理数据库之前的数据; 一般我们会写一个这样的方法
public class LogImpl implements LogService{
public void clear(){
logService.remove(new Date());
}
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
public class QuartzUtil { /** * 将新增的任务放入quartz调度中心中执行 * * @param sysJob 具体任务信息 * @throws Exception 异常 */ @SneakyThrows public static void insertOrUpdateJob(SysJob sysJob) { // 获取调度器 Scheduler Scheduler scheduler = SchedulerStatic.getScheduler(); Long jobId = sysJob.getJobId(); String jobGroup = sysJob.getJobGroup(); // 构造一个job JobKey jobKey = JobKey.jobKey(jobId.toString(), jobGroup); JobDetail jobDetail = JobBuilder .newJob(QuartzJob.class) .withIdentity(jobKey) .build(); // 构造cron调度器 CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(sysJob.getCronExpression()); getMisfirePolicy(sysJob, cronScheduleBuilder); // 构造触发器 trigger TriggerKey triggerKey = TriggerKey.triggerKey(jobId.toString(), jobGroup); CronTrigger trigger = TriggerBuilder .newTrigger() .withIdentity(triggerKey) .withSchedule(cronScheduleBuilder) .build(); // 放入job信息,为后续执行改任务的具体方法做铺垫(需要反射调用), 在execute中获取并应用 jobDetail.getJobDataMap().put(QuartzEnum.jobKey, sysJob); // 判断该任务是否存在,修改任务,先删除然后添加 if (scheduler.checkExists(jobKey)) { // 防止创建时存在数据问题 先移除,然后在执行创建操作 scheduler.deleteJob(jobKey); } // 判断任务是否过期 CronExpression cron = new CronExpression(sysJob.getCronExpression()); Date nextValidTimeAfter = cron.getNextValidTimeAfter(new Date(System.currentTimeMillis())); if (!ObjectUtils.isEmpty(nextValidTimeAfter)) { // 执行调度任务 scheduler.scheduleJob(jobDetail, trigger); } // 暂停任务 if (sysJob.getStatus().equals(QuartzEnum.PAUSE)) { scheduler.pauseJob(jobKey); } } /** * 根据计划执行错误策略,设置调度器 * * @param sysJob 任务信息 * @param cronScheduleBuilder cron调度器 */ private static void getMisfirePolicy(SysJob sysJob, CronScheduleBuilder cronScheduleBuilder) { switch (sysJob.getMisfirePolicy()) { case QuartzEnum.MISFIRE_DEFAULT: break; case QuartzEnum.MISFIRE_IGNORE_MISFIRES: cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires(); break; case QuartzEnum.MISFIRE_FIRE_AND_PROCEED: cronScheduleBuilder.withMisfireHandlingInstructionFireAndProceed(); break; case QuartzEnum.MISFIRE_DO_NOTHING: cronScheduleBuilder.withMisfireHandlingInstructionDoNothing(); break; default: throw new RuntimeException("The task misfire policy '" + sysJob.getMisfirePolicy() + "' cannot be used in cron schedule tasks"); } } /** * 删除任务 * * @param sysJob 具体任务信息(获取jobkey) */ @SneakyThrows public static void deleteJob(SysJob sysJob) { // 获取调度器 Scheduler Scheduler scheduler = SchedulerStatic.getScheduler(); scheduler.deleteJob(JobKey.jobKey(sysJob.getJobId().toString(), sysJob.getJobGroup())); } }
public class QuartzJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 获取任务执行参数 SysJob sysJob = (SysJob) context.getJobDetail().getJobDataMap().get(QuartzEnum.jobKey); // invokeTarget 应该符合 类.方法名 例如 task.sout() String invokeTarget = sysJob.getInvokeTarget(); String beanName = invokeTarget.split("\\.")[0]; String temp = invokeTarget.split("\\.")[1]; String methodName = temp.substring(0, temp.indexOf("(")); Object bean = SpringUtil.getBean(beanName); Method method = null; try { method = bean.getClass().getMethod(methodName); method.invoke(bean); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } }
@Component
public class SchedulerStatic {
private static Scheduler scheduler;
@Autowired
public SchedulerStatic(Scheduler scheduler) {
SchedulerStatic.scheduler = scheduler;
}
public static Scheduler getScheduler() {
return scheduler;
}
}
@Service("task")
public class MyTask {
@Autowired
SysJobService sysJobService;
/**
* 任务的具体执行逻辑写在此处,这里只做打印
*/
public void sout() {
List<SysJob> list = sysJobService.list();
list.forEach(sysJob -> System.out.println(sysJob.toString()));
}
}
spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/quartz?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true username: root password: root # 页面配置 mvc: path match: matching-strategy: ant_path_matcher server: port: 8889 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
可以看到,已经开始执行任务了,0/2 * * * * ? 每两秒后执行一次
执行的是打印
基本实现了任务的动态添加
后续完善:
项目地址: springboot-quartz
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。