公司之前的项目的定时任务都是使用@Schedule注解进行管理的;新需求需要实现对定时任务进行动态管理。后面决定用Quartz框架进行集成,以最小的代码来管理定时任务。
所需依赖:Springboot 1.xx 或 2.xx-RELEASE 都行, quartz 使用2.3.0版本
- <dependency>
- <groupId>org.quartz-schedulergroupId>
- <artifactId>quartzartifactId>
- <version>2.3.0version>
- dependency>
为了简单演示,只创建一个任务类用于修改定时任务实体类即可,创建任务实体类:QuartzBean
- @Data
- public class QuartzBean implements Serializable {
-
- private static final long serialVersionUID=1L;
-
- @TableId
- private String id;
-
- /**
- * 任务名称
- */
- private String jobName;
-
- /**
- * 任务执行类
- */
- private String jobClass;
-
- /**
- * 任务时间表达式
- */
- @NotNull
- private String cron;
-
- /**
- * 任务启动状态 0 运行中 1 已关闭
- */
- private Integer status;
-
- /**
- * 创建时间
- */
- private Date createTime;
- }
这里有三个配置类,分别为AutowiringSpringBeanJobFactory.java(主要是为了使得Job任务类运行时,可以注入其他service层)、QuartzConfig.java(quartz配置类,可设置对应的数据源,将schedule创建bean对象等)和 QuartzJobInitializer.java (用于项目启动时,可以从数据库里取出对应的QuartzBean对象,进行任务的自启动)
- import org.quartz.spi.TriggerFiredBundle;
- import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- import org.springframework.scheduling.quartz.SpringBeanJobFactory;
-
- /**
- * 功能说明: job配置可注入其他服务类
- */
- public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
- private transient AutowireCapableBeanFactory beanFactory;
-
- @Override
- public void setApplicationContext(ApplicationContext context) {
- beanFactory = context.getAutowireCapableBeanFactory();
- }
-
- @Override
- protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
- final Object job = super.createJobInstance(bundle);
- beanFactory.autowireBean(job);
- return job;
- }
- }
-
- import org.quartz.Scheduler;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.scheduling.quartz.SchedulerFactoryBean;
-
-
- /**
- * 功能说明: quartz配置类
- */
- @Configuration
- public class QuartzConfig {
-
-
- /** 暂不使用数据库进行quartz的持久化
- @Bean
- public Properties properties() throws IOException {
- PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
- // 对quartz.properties文件进行读取
- propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
- // 在quartz.properties中的属性被读取并注入后再初始化对象
- propertiesFactoryBean.afterPropertiesSet();
- return propertiesFactoryBean.getObject();
- }
- **/
-
- @Bean
- public AutowiringSpringBeanJobFactory autowiringSpringBeanJobFactory() {
- return new AutowiringSpringBeanJobFactory();
- }
-
-
- @Bean
- public SchedulerFactoryBean schedulerFactoryBean() {
- SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
- schedulerFactoryBean.setAutoStartup(true);
- schedulerFactoryBean.setJobFactory(autowiringSpringBeanJobFactory());
- // 从application.yml中读取Quartz的配置并设置到SchedulerFactoryBean中
- // schedulerFactoryBean.setQuartzProperties(properties());
- return schedulerFactoryBean;
- }
-
- /**
- * 通过SchedulerFactoryBean获取Scheduler的实例
- * @param schedulerFactoryBean
- * @return
- */
- @Bean
- public Scheduler scheduler(SchedulerFactoryBean schedulerFactoryBean) {
- return schedulerFactoryBean.getScheduler();
- }
-
- }
- @Slf4j
- @Component
- public class QuartzJobInitializer {
-
- @Autowired
- private Scheduler scheduler;
-
- @Autowired
- private IQuartzBeanService quartzBeanService;
-
- @Autowired
- public QuartzJobInitializer(Scheduler scheduler) {
- this.scheduler = scheduler;
- }
-
- @PostConstruct
- public void init(){
- log.info("quartz:默认启动所有开启状态的定时任务");
- List
quartzBeans = quartzBeanService.selectList(new EntityWrapper<>()); - List
executeJobs = quartzBeans.stream().filter(f -> QuartzEnums.TaskStatusEnum.RUNNING.getType().equals(f.getStatus())).collect(Collectors.toList()); - try {
- // 这里将会启动所有定时任务
- if (CollUtil.isNotEmpty(executeJobs)) {
- executeJobs.forEach(item -> QuartzUtils.createScheduleJob(scheduler, item));
- }
- }catch (Exception e) {
- log.error("自启动定时任务异常: {}",e);
- }
- }
-
- }
QuartzUtils类主要用于底层的创建、修改、删除、立即执行、暂停和恢复任务
- mport com.bean.QuartzBean;
- import lombok.extern.slf4j.Slf4j;
- import org.quartz.CronScheduleBuilder;
- import org.quartz.CronTrigger;
- import org.quartz.Job;
- import org.quartz.JobBuilder;
- import org.quartz.JobDetail;
- import org.quartz.JobKey;
- import org.quartz.Scheduler;
- import org.quartz.SchedulerException;
- import org.quartz.TriggerBuilder;
- import org.quartz.TriggerKey;
-
- /**
- * 功能说明: 定时任务执行工具类
- */
- @Slf4j
- public class QuartzUtils {
-
- /**
- * 创建定时任务 定时任务创建之后默认启动状态
- * @param scheduler
- * @param quartzBean
- */
- public static void createScheduleJob(Scheduler scheduler, QuartzBean quartzBean) {
- try {
- //获取到定时任务的执行类 必须是类的绝对路径名称
- //定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。
- Class extends Job> jobClass = (Class extends Job>)Class.forName(quartzBean.getJobClass());
- // 构建定时任务信息
- JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(quartzBean.getJobName()).build();
- // 设置定时任务执行方式
- CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCron());
- // 构建触发器trigger
- CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(quartzBean.getJobName()).withSchedule(scheduleBuilder).build();
- scheduler.scheduleJob(jobDetail, trigger);
- } catch (ClassNotFoundException e) {
- log.error("定时任务类路径出错:请输入类的绝对路径 {}",e.getMessage());
- } catch (SchedulerException e) {
- log.error("创建定时任务出错: {}", e.getMessage());
- }
- }
-
- /**
- * 根据任务名称暂停定时任务
- * @param scheduler
- * @param jobName
- */
- public static void pauseScheduleJob(Scheduler scheduler, String jobName) {
- JobKey jobKey = JobKey.jobKey(jobName);
- try {
- scheduler.pauseJob(jobKey);
- } catch (SchedulerException e) {
- log.error("暂停定时任务出错: {}", e.getMessage());
- }
- }
-
- /**
- * 根据任务名称恢复定时任务
- * @param scheduler
- * @param jobName
- */
- public static void resumeScheduleJob(Scheduler scheduler, String jobName) {
- JobKey jobKey = JobKey.jobKey(jobName);
- try {
- scheduler.resumeJob(jobKey);
- } catch (SchedulerException e) {
- System.out.println("恢复定时任务出错:"+e.getMessage());
- }
- }
-
- /**
- * 根据任务名称立即运行一次定时任务
- * @param scheduler
- * @param jobName
- */
- public static void runOnce(Scheduler scheduler, String jobName){
- JobKey jobKey = JobKey.jobKey(jobName);
- try {
- scheduler.triggerJob(jobKey);
- } catch (SchedulerException e) {
- System.out.println("运行定时任务出错:"+e.getMessage());
- }
- }
-
- /**
- * 更新定时任务
- * @param scheduler
- * @param quartzBean
- */
- public static void updateScheduleJob(Scheduler scheduler, QuartzBean quartzBean) {
- try {
- //获取到对应任务的触发器
- TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName());
- //设置定时任务执行方式
- CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCron());
- //重新构建任务的触发器trigger
- CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
- trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
- //重置对应的job
- scheduler.rescheduleJob(triggerKey, trigger);
- } catch (SchedulerException e) {
- System.out.println("更新定时任务出错:"+e.getMessage());
- }
- }
-
- /**
- * 根据定时任务名称从调度器当中删除定时任务
- * @param scheduler
- * @param jobName
- */
- public static void deleteScheduleJob(Scheduler scheduler, String jobName) {
- JobKey jobKey = JobKey.jobKey(jobName);
- try {
- scheduler.deleteJob(jobKey);
- } catch (SchedulerException e) {
- System.out.println("删除定时任务出错:"+e.getMessage());
- }
- }
-
- }
- import lombok.extern.slf4j.Slf4j;
- import org.quartz.DisallowConcurrentExecution;
- import org.quartz.JobExecutionContext;
- import org.quartz.JobExecutionException;
- import org.quartz.PersistJobDataAfterExecution;
- import org.springframework.scheduling.quartz.QuartzJobBean;
- import org.springframework.stereotype.Service;
-
- /**
- * 功能说明: 定时任务-MyQuartzTask
- */
- @Slf4j
- @Service
- @PersistJobDataAfterExecution
- @DisallowConcurrentExecution
- public class MyQuartzTask extends QuartzJobBean {
-
- @Override
- protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
- String jobName = jobExecutionContext.getJobDetail().getKey().getName();
- log.info("定时任务【{}】启动成功", jobName);
- }
- @Slf4j
- @RestController
- @RequestMapping("/quartz")
- public class QuartzController {
-
- @Autowired
- private Scheduler scheduler;
-
-
- /**
- * 创建定时任务
- * @param quartzVO
- * @return
- */
- @GetMapping("/createScheduleJob")
- public ResultVO createScheduleJob() {
- QuartzBean quartzBean = QuartzBean.builder()
- .jobName("任务名称唯一")
- .jobClass("com.service.impl.quartz.MyQuartzTask")
- .cron("0 0/2 * * * ?")
- .build();
- QuartzUtils.createScheduleJob(scheduler, quartzBean);
- return ResultVOUtil.success();
- }