diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/MafAutoConfiguration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/MafAutoConfiguration.java index dcca4ced..c9966e82 100644 --- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/MafAutoConfiguration.java +++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/MafAutoConfiguration.java @@ -14,6 +14,7 @@ import com.jmsoftware.maf.springcloudstarter.helper.HttpApiScanHelper; import com.jmsoftware.maf.springcloudstarter.helper.IpHelper; import com.jmsoftware.maf.springcloudstarter.helper.SpringBootStartupHelper; +import com.jmsoftware.maf.springcloudstarter.quartz.QuartzConfiguration; import com.jmsoftware.maf.springcloudstarter.redis.RedisConfiguration; import com.jmsoftware.maf.springcloudstarter.service.CommonService; import com.jmsoftware.maf.springcloudstarter.service.impl.CommonServiceImpl; @@ -64,7 +65,8 @@ RabbitmqConfiguration.class, MinioConfiguration.class, JacksonConfiguration.class, - TypeConversionConfiguration.class + TypeConversionConfiguration.class, + QuartzConfiguration.class }) public class MafAutoConfiguration { @PostConstruct diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/quartz/GreetingQuartzJobBean.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/quartz/GreetingQuartzJobBean.java new file mode 100644 index 00000000..8f982aa0 --- /dev/null +++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/quartz/GreetingQuartzJobBean.java @@ -0,0 +1,29 @@ +package com.jmsoftware.maf.springcloudstarter.quartz; + +import com.jmsoftware.maf.springcloudstarter.configuration.MafProjectProperty; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.quartz.JobExecutionContext; +import org.springframework.lang.NonNull; +import org.springframework.scheduling.quartz.QuartzJobBean; + +/** + * Description: GreetingQuartzJobBean, change description here. + * + * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 7/13/2021 10:16 PM + * @see + * Quartz Scheduler + **/ +@Slf4j +@RequiredArgsConstructor +public class GreetingQuartzJobBean extends QuartzJobBean { + /** + * Injected field, spring bean. + */ + private final MafProjectProperty mafProjectProperty; + + @Override + protected void executeInternal(@NonNull JobExecutionContext jobExecutionContext) { + log.info("Greeting from Quartz job, current service is: {}", mafProjectProperty.getProjectArtifactId()); + } +} diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/quartz/QuartzConfiguration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/quartz/QuartzConfiguration.java new file mode 100644 index 00000000..7bf35238 --- /dev/null +++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/quartz/QuartzConfiguration.java @@ -0,0 +1,55 @@ +package com.jmsoftware.maf.springcloudstarter.quartz; + +import com.jmsoftware.maf.springcloudstarter.configuration.MafProjectProperty; +import lombok.val; +import org.quartz.Scheduler; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Bean; +import org.springframework.scheduling.quartz.CronTriggerFactoryBean; +import org.springframework.scheduling.quartz.JobDetailFactoryBean; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; +import org.springframework.transaction.PlatformTransactionManager; + +import java.util.Optional; + +/** + * Description: QuartzConfiguration, change description here. + * + * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 7/13/2021 10:44 PM + **/ +@ConditionalOnClass({Scheduler.class, SchedulerFactoryBean.class, PlatformTransactionManager.class}) +public class QuartzConfiguration { + @Bean + public GreetingQuartzJobBean greetingQuartzJobBean(MafProjectProperty mafProjectProperty) { + return new GreetingQuartzJobBean(mafProjectProperty); + } + + @Bean("greetingQuartzJobDetailFactoryBean") + public JobDetailFactoryBean greetingQuartzJobDetailFactoryBean(GreetingQuartzJobBean greetingQuartzJobBean) { + val jobDetailFactoryBean = new JobDetailFactoryBean(); + jobDetailFactoryBean.setName("greeting-job-detail"); + jobDetailFactoryBean.setGroup("default"); + jobDetailFactoryBean.setJobClass(greetingQuartzJobBean.getClass()); + jobDetailFactoryBean.setDescription("Greeting job detail created by JobDetailFactoryBean"); + jobDetailFactoryBean.setDurability(true); + return jobDetailFactoryBean; + } + + @Bean("greetingQuartzJobCronTriggerFactoryBean") + public CronTriggerFactoryBean greetingQuartzJobCronTriggerFactoryBean( + @Qualifier("greetingQuartzJobDetailFactoryBean") JobDetailFactoryBean jobDetailFactoryBean) { + val cronTriggerFactoryBean = new CronTriggerFactoryBean(); + cronTriggerFactoryBean.setName("greeting-cron-trigger"); + cronTriggerFactoryBean.setGroup("default"); + cronTriggerFactoryBean.setCronExpression("0 0/1 * 1/1 * ? *"); + val optionalJobDetail = Optional.ofNullable(jobDetailFactoryBean.getObject()); + optionalJobDetail.ifPresent(cronTriggerFactoryBean::setJobDetail); + return cronTriggerFactoryBean; + } + + @Bean + public QuartzJobService quartzJobService(SchedulerFactoryBean schedulerFactoryBean) { + return new QuartzJobServiceImpl(schedulerFactoryBean); + } +} diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/quartz/QuartzJobService.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/quartz/QuartzJobService.java new file mode 100644 index 00000000..7d915f40 --- /dev/null +++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/quartz/QuartzJobService.java @@ -0,0 +1,83 @@ +package com.jmsoftware.maf.springcloudstarter.quartz; + +import java.util.Map; + +/** + * Description: QuartzJobService, change description here. + * + * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 7/13/2021 10:17 PM + */ +public interface QuartzJobService { + /** + * 添加任务可以传参数 + * + * @param clazzName the clazz name + * @param jobName the job name + * @param groupName the group name + * @param cronExp the cron exp + * @param param the param + */ + void addJob(String clazzName, String jobName, String groupName, String cronExp, Map param); + + /** + * 暂停任务 + * + * @param jobName the job name + * @param groupName the group name + */ + void pauseJob(String jobName, String groupName); + + /** + * 恢复任务 + * + * @param jobName the job name + * @param groupName the group name + */ + void resumeJob(String jobName, String groupName); + + /** + * 立即运行一次定时任务 + * + * @param jobName the job name + * @param groupName the group name + */ + void runOnce(String jobName, String groupName); + + /** + * 更新任务 + * + * @param jobName the job name + * @param groupName the group name + * @param cronExp the cron exp + * @param param the param + */ + void updateJob(String jobName, String groupName, String cronExp, Map param); + + /** + * 删除任务 + * + * @param jobName the job name + * @param groupName the group name + */ + void deleteJob(String jobName, String groupName); + + /** + * 启动所有任务 + */ + void startAllJobs(); + + /** + * 暂停所有任务 + */ + void pauseAllJobs(); + + /** + * 恢复所有任务 + */ + void resumeAllJobs(); + + /** + * 关闭所有任务 + */ + void shutdownAllJobs(); +} diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/quartz/QuartzJobServiceImpl.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/quartz/QuartzJobServiceImpl.java new file mode 100644 index 00000000..dbf9c259 --- /dev/null +++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/quartz/QuartzJobServiceImpl.java @@ -0,0 +1,143 @@ +package com.jmsoftware.maf.springcloudstarter.quartz; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.quartz.*; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; + +import java.util.Map; + +/** + * Description: QuartzJobServiceImpl, change description here. + * + * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 7/13/2021 10:18 PM + * @see SpringBoot 整合 Quartz 实现分布式调度 + **/ +@Slf4j +@RequiredArgsConstructor +public class QuartzJobServiceImpl implements QuartzJobService { + private final SchedulerFactoryBean schedulerFactoryBean; + + @Override + public void addJob(String clazzName, String jobName, String groupName, String cronExp, Map param) { + try { + // 构建job信息 + @SuppressWarnings("unchecked") Class jobClass = + (Class) Class.forName(clazzName); + JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, groupName).build(); + // 表达式调度构建器(即任务执行的时间) + CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExp); + // 按新的cronExpression表达式构建一个新的trigger + CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, groupName).withSchedule( + scheduleBuilder).build(); + // 获得JobDataMap,写入数据 + if (param != null) { + trigger.getJobDataMap().putAll(param); + } + schedulerFactoryBean.getScheduler().scheduleJob(jobDetail, trigger); + } catch (Exception e) { + log.error("创建任务失败", e); + } + } + + @Override + public void pauseJob(String jobName, String groupName) { + try { + schedulerFactoryBean.getScheduler().pauseJob(JobKey.jobKey(jobName, groupName)); + } catch (SchedulerException e) { + log.error("暂停任务失败", e); + } + } + + @Override + public void resumeJob(String jobName, String groupName) { + try { + schedulerFactoryBean.getScheduler().resumeJob(JobKey.jobKey(jobName, groupName)); + } catch (SchedulerException e) { + log.error("恢复任务失败", e); + } + } + + @Override + public void runOnce(String jobName, String groupName) { + try { + schedulerFactoryBean.getScheduler().triggerJob(JobKey.jobKey(jobName, groupName)); + } catch (SchedulerException e) { + log.error("立即运行一次定时任务失败", e); + } + } + + @Override + public void updateJob(String jobName, String groupName, String cronExp, Map param) { + try { + TriggerKey triggerKey = TriggerKey.triggerKey(jobName, groupName); + CronTrigger trigger = (CronTrigger) schedulerFactoryBean.getScheduler().getTrigger(triggerKey); + if (cronExp != null) { + // 表达式调度构建器 + CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExp); + // 按新的cronExpression表达式重新构建trigger + trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); + } + //修改map + if (param != null) { + trigger.getJobDataMap().putAll(param); + } + // 按新的trigger重新设置job执行 + schedulerFactoryBean.getScheduler().rescheduleJob(triggerKey, trigger); + } catch (Exception e) { + log.error("更新任务失败", e); + } + } + + @Override + public void deleteJob(String jobName, String groupName) { + try { + //暂停、移除、删除 + schedulerFactoryBean.getScheduler().pauseTrigger(TriggerKey.triggerKey(jobName, groupName)); + schedulerFactoryBean.getScheduler().unscheduleJob(TriggerKey.triggerKey(jobName, groupName)); + schedulerFactoryBean.getScheduler().deleteJob(JobKey.jobKey(jobName, groupName)); + } catch (Exception e) { + log.error("删除任务失败", e); + } + } + + @Override + public void startAllJobs() { + try { + schedulerFactoryBean.start(); + } catch (Exception e) { + log.error("开启所有的任务失败", e); + } + } + + @Override + public void pauseAllJobs() { + try { + schedulerFactoryBean.getScheduler().pauseAll(); + } catch (Exception e) { + log.error("暂停所有任务失败", e); + } + } + + @Override + public void resumeAllJobs() { + try { + schedulerFactoryBean.getScheduler().resumeAll(); + } catch (Exception e) { + log.error("恢复所有任务失败", e); + } + } + + @Override + public void shutdownAllJobs() { + try { + if (!schedulerFactoryBean.getScheduler().isShutdown()) { + // 需谨慎操作关闭scheduler容器 + // scheduler生命周期结束,无法再 start() 启动 scheduler + schedulerFactoryBean.getScheduler().shutdown(true); + } + } catch (Exception e) { + log.error("关闭所有的任务失败", e); + } + } +}