springboot quartz 手写任务调度

原创
2020/07/16 17:40
阅读数 508

添加引用

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

QuartzFactory类:主要用于解决springboot quartz  job 无法注入bean的问题。

package com.example.springboot;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

@Component
public class QuartzFactory extends AdaptableJobFactory {

    /**
     * AutowireCapableBeanFactory接口是BeanFactory的子类
     * 可以连接和填充那些生命周期不被Spring管理的已存在的bean实例
     */
    private AutowireCapableBeanFactory factory;

    public QuartzFactory(AutowireCapableBeanFactory factory) {
        this.factory = factory;
    }

    /**
     * 创建Job实例
     */
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        // 实例化对象
        Object job = super.createJobInstance(bundle);
        // 进行注入(Spring管理该Bean        factory.autowireBean(job);
        //返回对象
        return job;
    }

}

 

QuartzConfig类:主要用于解决springboot quartz  job 无法注入bean的问题,需要配合QuartzFactory类。

package com.example.springboot;

import org.quartz.Scheduler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

@Configuration
public class QuartzConfig {

    private QuartzFactory quartzFactory;

    public QuartzConfig(QuartzFactory quartzFactory) {
        this.quartzFactory = quartzFactory;
    }

    /**
     * 配置SchedulerFactoryBean
     * 将一个方法产生为Bean并交给Spring容器管理
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
        // Spring提供SchedulerFactoryBeanScheduler提供配置信息,并被Spring容器管理其生命周期
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        // 设置自定义Job Factory,用于Spring管理Job bean
        factory.setJobFactory(quartzFactory);
        return factory;
    }

    @Bean(name = "scheduler")
    public Scheduler scheduler() {
        return schedulerFactoryBean().getScheduler();
    }

}

 

QuartzService类:封装一些任务调度的东西,主要也用于测试注入job的bean对象。

package com.example.springboot;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;

@Slf4j
@Service
public class QuartzService {

    @Autowired
    private Scheduler scheduler;

    // 添加调度任务
    public Boolean addScheduler(Integer id, String cron) throws Exception {
        // 判断,如果因为意外将过期调度任务传递过来,进行排除
        // ...

        // 添加一个去重复的操作
        if (scheduler.getJobDetail(JobKey.jobKey(id.toString())) != null) {
            return Boolean.TRUE;
        }

        // 构建一个job
        JobDetail jobDetail = JobBuilder
                .newJob(QuartzJob.class)
                .withIdentity(id.toString())
                .usingJobData("param", id.toString())
                .build();

        // 构建一个trigger
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(id.toString())
                .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                .build();

        // 构建一个scheduler
        Date nextExecuteTime = scheduler.scheduleJob(jobDetail, trigger);
        //开始执行
        scheduler.start();
        return Boolean.TRUE;
    }

    // 取消调度任务,并且清除缓存
    public Boolean deleteJob(Integer id) {
        Boolean result = Boolean.FALSE;
        try {
            // 删除job
            result = scheduler.deleteJob(JobKey.jobKey(id.toString()));
        } catch (Exception ex) {
            // 记录个日志
            log.error(String.format("%s-删除调度器出现异常:%s,堆栈信息:%s", id, ex.getMessage(), ExceptionUtils.getStackTrace(ex)));
        }
        return result;
    }

    // 查询调度任务
    public Boolean query(Integer id) throws Exception {
        JobDetail jobDetail = scheduler.getJobDetail(JobKey.jobKey(id.toString()));
        if (jobDetail == null) {
            return Boolean.FALSE;
        } else {
            return Boolean.TRUE;
        }
    }

    // 得到cron的下一次执行时间
    public String getNextExecuteTime(String cron) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 验证cron的正确性
        System.out.println(CronExpression.isValidExpression(cron));
        if (CronExpression.isValidExpression(cron)) {
            CronTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("default")
                    .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                    .build();
            // 获取到下一次执行时间
            Date nextTime = trigger.getFireTimeAfter(trigger.getStartTime());
            return df.format(nextTime);
        } else {
            return "表达式不合法";
        }
    }

}

 

QuartzJob类:就是job要执行的类,该类如果不做特殊处理,是无法将bean对象注入该类的。重点就是QuartzFactory和QuartzConfig两个类的添加,没有什么需要特别注意的东西。

package com.example.springboot;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class QuartzJob implements Job {

    // 正常情况下,这里是注入不进来的,故意写个来检验注入bean问题
    @Autowired
    private QuartzService quartzService;

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        try {
            JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
            // 获取参数
            String param = jobDataMap.getString("param");
            System.out.println(param + "——开始执行");
            Thread.sleep(1000);
            // 调用删除调度器的方法
            Boolean result = quartzService.deleteJob(Integer.valueOf(param));
            System.out.println(param + "——执行结束,取消调度任务结果:" + result);
        } catch (Exception ex) {
            log.error(String.format("执行调度器出现异常:%s,堆栈信息:%s", ex.getMessage(), ExceptionUtils.getStackTrace(ex)));
        }

    }
}

 

QuartzController类:测试类,用于调用任务的添加,删除和查询。

package com.example.springboot;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@Slf4j
@RestController
public class QuartzController {

    @Autowired
    private QuartzService quartzService;

    @RequestMapping("/quartz/add/{id}")
    private Boolean index(@PathVariable Integer id, @RequestBody String cron) throws Exception {
        Boolean result = quartzService.addScheduler(id, cron);
        return result;
    }

    @RequestMapping("/quartz/delete/{id}")
    public Boolean cancel(@PathVariable Integer id) {
        Boolean result = quartzService.deleteJob(id);
        return result;
    }

    @RequestMapping("/quartz/query/{id}")
    public Boolean query(@PathVariable Integer id) throws Exception {
        Boolean result = quartzService.query(id);
        return result;
    }

}

 

注意:由于job类无法注入spring bean对象,因此需要添加QuartzFactory和QuartzConfig两个类,然后Scheduler调用方式,不是采用new,而是注入的方式,参见QuartzService中的Scheduler使用

 

CronExpression cronExpression = new CronExpression("30 30 17 * * ? ");
//这个方法没有实现
System.out.println("getFinalFireTime - " + cronExpression.getFinalFireTime());
//得到给定时间下一个无效的时间
System.out.println("GetNextInvalidTimeAfter - " + cronExpression.getNextInvalidTimeAfter(new Date()));
//得到给定时间的下一个有效的时间
System.out.println("GetNextValidTimeAfter - " + cronExpression.getNextValidTimeAfter(new Date()));
//得到给定时间下一个符合表达式的时间
System.out.println("GetTimeAfter - " + cronExpression.getTimeAfter(new Date()));
//这个方法没有实现
System.out.println("GetTimeBefore - " + cronExpression.getTimeBefore(new Date()));
//给定时间是否符合表达式
System.out.println("IsSatisfiedBy - " + cronExpression.isSatisfiedBy(new Date()));

 

吐槽一下,网上代码都是各种copy,找点有用的找不到。就想找为什么job类无法注入,解决方案都找半天没有用,后来自己总结搞了下,其实就是添加两个类就可以了,很简单,非得贴一大坨代码,也没有说明解释。springboot quartz无法注入问题参见上述红字把。

 

 

展开阅读全文
打赏
0
1 收藏
分享
加载中
更多评论
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部