Java实现定时任务调度之Quartz篇

一、了解Quartz
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,Quartz 是一个完全由 Java 编写的开源作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制,可以与 J2EE与 J2SE应用程序相结合使用也可以单独使用。其允许程序开发人员根据时间的间隔来调度作业。
Quartz 实现了作业和触发器的多对多的关系,还能把多个作业与不同的触发器关联。

Quartz 的几个核心概念:
1.Job 表示一个工作,要执行的具体内容。此接口中只有一个方法void execute(JobExecutionContext context)
2.JobDetail 表示一个具体的可执行的调度程序,Job是这个可执行程调度程序所要执行的内容,另外 JobDetail 还包含了这个任务调度的方案和策略。
3.Trigger 代表一个调度参数的配置,什么时候去调。
4.Scheduler 代表一个调度容器,一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调度了。

二、Quartz的第一种使用方式
上面说到了Quartz既可以与 J2EE以及 J2SE应用程序相结合使用也可以单独使用,这里就先介绍一下单独使用的方法。
既然是单独使用,也就是说我们只需要一个main函数就可以开始一个调度任务。在进行Quartz调度时,最重要的三部分就是Job、Trigger、Scheduler,分别为任务、触发器和调度器。

把三者的关系打个比方,Scheduler就像是Boss主公,他是整个团队的核心领袖,负责整个调度运行的环境。而Trigger就像是谋士军师,他有整个工作要如何运行的标准。最后的Job就像是小兵,来执行老板下发的命令,以及Trigger告诉他要如何执行怎么执行,这样Job就去做准确的调度任务(可能不是特别准确,大家自己理解一下)。

第一步,需要添加Quartz依赖

		<dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
        </dependency>

首先,创建我们的调度任务类,该类实现 Job接口,只有一个execute方法需要重写,我们把需要的相关业务代码写在此方法中,最后会将该方法加入调度器中执行。

/**
 * @author Edwin
 * @description 调度任务类
 **/
public class QuartzTaskJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("执行目标操作中...");
    }
}

第二部分代码便是上面提到的,需要创建调度器 Scheduler、触发器 Trigger、及任务实例Job,这样我们就可以对该任务进行以我们赋予的标准或规则进行调度,下面是main函数中的代码

/**
 * @author Edwin
 * @description 调度控制类
 **/
public class MyScheduler {

    public static void main(String[] args) throws SchedulerException, InterruptedException {

        //创建调度器Scheduler
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        //创建JobDetail
        JobDetail jobDetail = JobBuilder.newJob(QuartzTaskJob.class)
                .withIdentity("jobDetail", "group1").build();
        //创建触发器Trigger
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "groupOfTrigger1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                //每隔5秒执行一次
                .withIntervalInSeconds(5)
                .repeatForever()).build();

        scheduler.scheduleJob(jobDetail, trigger);
        System.out.println("调度开始执行...");
        scheduler.start();

    }
}

Java实现定时任务调度之Quartz篇_第1张图片
以上就是一个简单的定时调度的方法,下面

三、Spring boot 整合 Quartz

首先一步,还是需要在spring boot启动类上加上一个必不可少的注解 @EnableScheduling,这一步与spring boot自带的使用注解 @Scheduled做定时调度相同。

@SpringBootApplication
@EnableScheduling
public class CollectApplication {

    public static void main(String[] args) {
        SpringApplication.run(CollectApplication.class, args);
    }
}

其次,在第一种Quartz的使用方法中我们用到了一个调度任务类,这里还是需要这个类,并实现Job接口和它的execute方法。

public class QuartzTaskJob implements Job {

    @Resource
    private JobService jobService;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        System.out.println("jobService " + jobService.printSomeThing());
        System.out.println("执行目标操作中...");
    }
}

需要注意的一点,在上面介绍的第一种Quartz的使用方法中,在任务类里是无法注入spring boot的service的!!!
例如,在QuartzTaskJob类中写上

	@Resource
    private JobService jobService;

这是无效的,因为实例Job对象与上面注入的JobService是在不同的地方,Job对象的实例化是在Quartz中进行的,而JobService自然是由Spring容器本身来处理的。因此Quartz并不认识JobService,所以就无法使用它了。

于是,就有了第三步,需要创建一个Quartz工厂类并继承 AdaptableJobFactory类。在这个类里我们用到的一个不常见的类 AutowireCapableBeanFactory,AutowireCapableBeanFactory拥有自动装配功能,就像 Spring容器一样具有管理 Bean对象的能力。它在BeanFactory基础上实现了对实例的管理,可以使用这个接口集成其它框架,捆绑并填充并不由Spring管理生命周期并已存在的实例。这里就是将继承的父类AdaptableJobFactory创建出的 jobDetail对象放入该容器中。以下就是Quartz工厂类代码

//不要忘记 @Component注解
@Component
public class QuartzTaskFactory extends AdaptableJobFactory {
   
    @Resource
    private AutowireCapableBeanFactory autowireCapableBeanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        
		//创建JobDetail对象
        Object jobDetail = super.createJobInstance(bundle);
        //将jobDetail对象加入到Spring容器中
        this.autowireCapableBeanFactory.autowireBean(jobDetail);
        return jobDetail;
    }
}

接下来最后一个重要的部分,在整合过程中我们需要创建一个Quartz配置类,在配置类中给容器注入我们重要的三个工厂类,SchedulerFactoryBean、CronTriggerFactoryBean或SimpleTriggerFactoryBean、JobDetailFactoryBean,其实就是分别对应着上面讲到的三个重要部分任务调度器 Scheduler、触发器 Trigger以及任务 Job,并对这三个类进行自己想要的操作。
先来依次认识一下这几个FactoryBean,最后我会把整个Quartz配置类的代码贴出来。

JobDetailFactoryBean:
spring对这个类的解释为:A Spring FactoryBean for creating a Quartz JobDetail instance, supporting bean-style usage for JobDetail configuration.一个用于创建Quartz JobDetail实例的,支持以bean定义风格来配置JobDetail的工厂bean。

	@Bean
    public JobDetailFactoryBean injectJobDetailFactoryBean(){

        log.info("注入JobDetailFactoryBean...");
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        //加入所要执行的任务Job
        factoryBean.setJobClass(QuartzTaskJob.class);
        return factoryBean;
    }

CronTriggerFactoryBean和SimpleTriggerFactoryBean:
创建自己的TriggerFactoryBean触发器对象,构造调度触发标准,有两种形式的TriggerFactoryBean:
1.simpleTrigger 必须要配置两个属性,startDelay表示系统启动后多长时间开始执行第一次任务。repeatInterval表示执行任务的时间间隔。
2.cronTrigger 是用cron表达式来执行定时任务,与spring boot中 @Scheduled的配置cron相同,可以看上一篇文章中cron的使用。

	@Bean(name="cronTriggerFactoryBean1")
    public CronTriggerFactoryBean injectCronTriggerFactoryBean(){

        log.info("注入CronTriggerFactoryBean...");
        CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
        JobDetailFactoryBean jobDetailFactoryBean = this.injectJobDetailFactoryBean();
        cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
        //加入cron表达式,每五秒执行一次Job
        cronTriggerFactoryBean.setCronExpression("0/5 * * * * ?");
        return cronTriggerFactoryBean;
    }
	@Bean(name="simpleTriggerFactoryBean1")
    public SimpleTriggerFactoryBean injectSimpleTriggerFactoryBean(){

        SimpleTriggerFactoryBean simpleTriggerFactoryBean = new SimpleTriggerFactoryBean();
        JobDetailFactoryBean jobDetailFactoryBean = this.injectJobDetailFactoryBean();
        simpleTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
        //程序启动后多久开始执行任务,单位ms 1000 = 一秒
        simpleTriggerFactoryBean.setStartDelay(10000);
        //每次定时任务的间隔时间(每隔多久执行一次),单位与上同
        simpleTriggerFactoryBean.setRepeatInterval(5000);
        return simpleTriggerFactoryBean;
    }

SchedulerFactoryBean:
SchedulerFactoryBean主导着定时任务的初始化与执行顺序,SchedulerFactoryBean的常用属性:
triggers:triggers属性为Trigger[]类型,可以通过该属性注册多个Trigger
JobFactory:为Scheduler设置JobDetail的工厂。可以覆盖掉SpringBoot提供的默认工厂,保证JobDetail中的自动装配有效
calendars:类型为Map,通过该属性向Scheduler注册Calendar
jobDetails:类型为JobDetail[],通过该属性向Scheduler注册JobDetail
autoStartup:SchedulerFactoryBean在初始化后是否马上启动Scheduler,默认为true。如果设置为false,需要手工启动Scheduler
startupDelay:在SchedulerFactoryBean初始化完成后,延迟多长时间启动Scheduler

	@Bean
    public SchedulerFactoryBean injectSchedulerFactoryBean(QuartzTaskFactory quartzTaskFactory, CronTriggerFactoryBean[] cronTriggerFactoryBean(或者使用SimpleTriggerFactoryBean)){

        log.info("注入SchedulerFactoryBean...");
        SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
        CronTrigger[] triggers = new CronTrigger[cronTriggerFactoryBean.length];
        for(int i = 0; i < cronTriggerFactoryBean.length; i++){
            triggers[i] = cronTriggerFactoryBean[i].getObject();
        }
        //注册触发器,一个Scheduler可以注册若干触发器
        factoryBean.setTriggers(triggers);
        //为Scheduler设置JobDetail的工厂。可以覆盖掉SpringBoot提供的默认工厂,保证JobDetail中的自动装配有效。
        factoryBean.setJobFactory(quartzTaskFactory);
        return factoryBean;
    }

这样就完成了一个Quartz定时调度,下面贴上配置类的完整代码以方便大家使用。这些只是使用Quartz做较简单的调度工作,后面遇到其他业务中的使用或操作后再做新的文章。

@Configuration
@Slf4j
public class QuartzTaskConfiguration {

    /**
     * spring对这个类的解释为:A Spring FactoryBean for creating a Quartz JobDetail instance,
     * supporting bean-style usage for JobDetail configuration.
     * 一个用于创建Quartz JobDetail实例的,支持以bean定义风格来配置JobDetail的工厂bean。
     */
    @Bean
    public JobDetailFactoryBean injectJobDetailFactoryBean(){

        log.info("注入JobDetailFactoryBean...");
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        //加入所要执行的任务Job
        factoryBean.setJobClass(QuartzTaskJob.class);
        return factoryBean;
    }

    /**
     * 定义自己的Trigger对象,有两种形式:
     * 1.simpleTrigger 必须要配置两个属性,startDelay表示系统启动后多长时间开始执行第一次任务。repeatInterval表示执行任务的时间间隔。
     * 2.cronTrigger 是用cron表达式来执行定时任务,与spring boot中 @Scheduled的配置cron相同,可以看上一篇文章。
     */
    @Bean(name="cronTriggerFactoryBean1")
    public CronTriggerFactoryBean injectCronTriggerFactoryBean(){

        log.info("注入CronTriggerFactoryBean...");
        CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
        JobDetailFactoryBean jobDetailFactoryBean = this.injectJobDetailFactoryBean();
        cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
        //加入cron表达式,每五秒执行一次Job
        cronTriggerFactoryBean.setCronExpression("0/5 * * * * ?");
        return cronTriggerFactoryBean;
    }
    
    /**
     * 这里使用的是 CronTriggerFactoryBean触发方式
     */
    @Bean
    public SchedulerFactoryBean injectSchedulerFactoryBean(QuartzTaskFactory quartzTaskFactory, CronTriggerFactoryBean[] cronTriggerFactoryBean){

        log.info("注入SchedulerFactoryBean...");
        SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
        CronTrigger[] triggers = new CronTrigger[cronTriggerFactoryBean.length];
        for(int i = 0; i < cronTriggerFactoryBean.length; i++){
            triggers[i] = cronTriggerFactoryBean[i].getObject();
        }
        //注册触发器,一个Scheduler可以注册若干触发器
        factoryBean.setTriggers(triggers);
        //为Scheduler设置JobDetail的工厂。可以覆盖掉SpringBoot提供的默认工厂,保证JobDetail中的自动装配有效。
        factoryBean.setJobFactory(quartzTaskFactory);
        return factoryBean;
    }

}

Java实现定时任务调度之Quartz篇_第2张图片
点关注 不迷路,一起解决更多问题,微信公众号:非定义式程序员

Java实现定时任务调度之Quartz篇_第3张图片

你可能感兴趣的:(实际方法专栏,java,quartz,定时任务)