栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Quartz学习笔记之快速入门

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Quartz学习笔记之快速入门

Quartz学习笔记 一、什么是Quartz

什么是Quartz?

Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,完全由Java开发,可以用来执行定时任务,类似于java.util.Timer。但是相较于Timer, Quartz增加了很多功能:

持久性作业 - 就是保持调度定时的状态;
作业管理 - 对调度作业进行有效的管理;

ps: 大部分公司都会用到定时任务这个功能。
拿火车票购票来说,当你下单后,后台就会插入一条待支付的task(job),一般是30分钟,超过30min后就会执行这个job,去判断你是否支付,未支付就会取消此次订单;当你支付完成之后,后台拿到支付回调后就会再插入一条待消费的task(job),Job触发日期为火车票上的出发日期,超过这个时间就会执行这个job,判断是否使用等。

在我们实际的项目中,当Job过多的时候,肯定不能人工去操作,这时候就需要一个任务调度框架,帮我们自动去执行这些程序。那么该如何实现这个功能呢?

(1)首先我们需要定义实现一个定时功能的接口,我们可以称之为Task(或Job),如定时发送邮件的task(Job),重启机器的task(Job),优惠券到期发送短信提醒的task(Job),实现接口如下:

(2)有了任务之后,还需要一个能够实现触发任务去执行的触发器,触发器Trigger最基本的功能是指定Job的执行时间,执行间隔,运行次数等。

(3)有了Job和Trigger后,怎么样将两者结合起来呢?即怎样指定Trigger去执行指定的Job呢?这时需要一个Schedule,来负责这个功能的实现。

上面三个部分就是Quartz的基本组成部分:

  • 调度器:Scheduler
  • 任务:JobDetail
  • 触发器:Trigger,包括SimpleTrigger和CronTrigger

那么明白 Quartz了 的几个核心概念,这样理解起 Quartz 的原理就会变得简单了。

  1. Job 表示一个工作,要执行的具体内容。类似于TimerTask类。需要实现方法 void execute(JobExecutionContext context)
  2. JobDetail 表示一个具体的可执行的调度程序,Job 是这个可执行程调度程序所要执行的内容,另外 JobDetail 还包含了这个任务调度的方案和策略。
  3. Trigger 代表一个调度参数的配置,什么时候去调。
  4. Scheduler 代表一个调度容器。类似于Timer类。一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调用。
  5. JobListener: 任务执行的监听器,可以监听到任务执行前、后以及未能成功执行抛出异常。
二、快速开始

SpringBoot集成Quartz依然沿用了Spring的典型方式,使用工厂Bean生成Bean的方式。在Quartz中,需要被调度的任务叫做Job,而负责调度任务则是Scheduler。
我们首先需要配置工厂Bean:JobFactory接口,自定义一个AutowiringSpringBeanJobFactory类继承SpringBeanJobFactory(实现了JobFactory接口)

AutowiringSpringBeanJobFactory工厂类将负责生成实现了Job接口的类的实例对象Bean。

1. 第一种集成 Springboot项目启动就执行


 org.quartz-scheduler
 quartz
 2.2.1

快速入门,2步搞定
1.启动类上面加 @EnableScheduling
2.方法上面加上@Scheduled(cron = "0/3 * * * * ? ") 每3秒执行一次

cron资料: https://www.cnblogs.com/javahr/p/8318728.html

然后就可以启动看结果了!!!

2. 第二种动态开启定时任务 1.引入依赖(Springboot项目)
     
         org.springframework.boot
         spring-boot-starter
     
     
         org.projectlombok
         lombok
         true
     
     
         org.springframework.boot
         spring-boot-starter-test
         test
     
     
     
         mysql
         mysql-connector-java
         8.0.26
     
     
     
         org.mybatis.spring.boot
         mybatis-spring-boot-starter
         1.3.2
     
     
     
         org.springframework.boot
         spring-boot-starter-jdbc
     
     
     
         org.springframework.boot
         spring-boot-starter-web
     
     
      
         org.quartz-scheduler
         quartz
         2.2.1
         
             
                 slf4j-api
                 org.slf4j
             
         
     
2.配置文件可选配置
#是否开启监听器 -> 可以不写,默认为不开启
jobListener:
  switch: true
3.创建一个执行任务的job类
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

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


public class helloJob implements Job{

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 取出JobDataMap中的数据 
        System.out.println(jobExecutionContext.getJobDetail().getJobDataMap().get("jobDetail1"));
        System.out.println(jobExecutionContext.getTrigger().getJobDataMap().get("trigger1"));
        System.out.println("定时任务执行啦:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }
}
3.创建JobListener监听器
package com.demo.quartz.config;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@Component
public class SchedulerListener implements JobListener {
    public static final String LISTENER_NAME = "QuartSchedulerListener";

    @Override
    public String getName() {
        return LISTENER_NAME; //must return a name
    }

    //任务被调度前
    @Override
    public void jobToBeExecuted(JobExecutionContext context) {

        String jobName = context.getJobDetail().getKey().toString();
        System.out.println("任务被调度前");
        System.out.println("Job : " + jobName + " is going to start...");

    }

    //任务调度被拒了
    @Override
    public void jobExecutionVetoed(JobExecutionContext context) {
        System.out.println("任务调度被拒了");
        //可以做一些日志记录原因
    }

    //任务被调度后
    @Override
    public void jobWasExecuted(JobExecutionContext context,
                               JobExecutionException jobException) {
        System.out.println("任务被调度后");

        String jobName = context.getJobDetail().getKey().toString();
        System.out.println("Job : " + jobName + " is finished...");

        if (jobException!=null&&!jobException.getMessage().equals("")) {
            System.out.println("Exception thrown by: " + jobName
                    + " Exception: " + jobException.getMessage());
        }
    }
    
}

4.创建SchedulerConfig配置类
package com.demo.quartz.config;

import lombok.SneakyThrows;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.spi.JobFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import java.io.IOException;
import java.util.Properties;


@Configuration
public class SchedulerConfig {

    @Autowired
    private SchedulerListener scheduleListener;

   // 是否开启监听器  默认为false
    @Value("${jobListener.switch:false}")
    private boolean jobListener;


    @Bean
    public SchedulerFactory schedulerFactoryBean(){
        return new StdSchedulerFactory();
    }

    @SneakyThrows
    @Bean
    public Scheduler scheduler(@Qualifier("schedulerFactoryBean") SchedulerFactory schedulerFactoryBean){
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        if(jobListener){
            scheduler.getListenerManager().addJobListener(scheduleListener);
        }
        return scheduler;
    }
}

5.自定义接口请求 执行定时任务
import com.demo.quartz.config.helloJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.TimeUnit;


@RestController
public class JobController {

    // 调度器
    @Autowired
    private Scheduler scheduler;

    // @Scheduled(cron = "0/3 * * * * ? ")
    public void text(){
        //每3秒执行一次
        System.out.println("定时任务执行啦:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }

    
    @PostMapping(value = "testTask1")
    public void testTask1( )throws SchedulerException {

        //可用于传值给job   具体看helloJob类如何取值使用
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("jobDetail1","jobDetail1");
        JobDataMap jobDataMap2 = new JobDataMap();
        jobDataMap2.put("trigger1","这是jobDetail1的trigger");

        // 1、创建JobDetail实例,并与PrintWordsJob类绑定(Job执行内容)
        JobDetail jobDetail = JobBuilder.newJob(helloJob.class).usingJobData(jobDataMap)
                .withIdentity("job1", "group1").build();

        // 2、构建Trigger(触发器)实例,每隔1s执行一次
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
                .usingJobData(jobDataMap2) //存值到jobDataMap Job类中能取出
                // 可设置触发时间
                .startNow()//立即生效
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(1)//每隔1s执行一次
                 .repeatForever()).build();//一直执行
        //3、执行
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
    }

    
    @PostMapping(value = "testTask2")
    public void testTask2( )throws SchedulerException {

        // 获取一周后的日期
        Date endDate = new Date();
        Calendar now = Calendar.getInstance();
        now.add(Calendar.DATE, +7);
        Date endAt = now.getTime();

        //可用于传值给job
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("jobDetail1","jobDetail1");
        JobDataMap jobDataMap2 = new JobDataMap();
        jobDataMap2.put("trigger1","这是jobDetail1的trigger");

        // 1、创建JobDetail实例,并与PrintWordsJob类绑定(Job执行内容)
        JobDetail jobDetail = JobBuilder.newJob(helloJob.class).usingJobData(jobDataMap)
                .withIdentity("job1", "group1").build();
        // 2、构建Trigger实例,每隔1s执行一次
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
                .usingJobData(jobDataMap2) //存值到jobDataMap
                
                .startNow() // 立即触发
                .endAt(endAt) // 表示该任务在一周后自动停止   ps:表示触发器结束触发的时间;
                //使用cron表达式    每天中午8点触发
                .withSchedule(CronScheduleBuilder.cronSchedule("0 0 8 * * ?"))
                .build();

        //3、执行
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
    }

    
    @PostMapping(value = "testTask3")
    public void testTask3( )throws SchedulerException {


        Calendar now = Calendar.getInstance();
        now.setTime(new Date());
        // 获取一周后的日期
        now.add(Calendar.DATE, +7);
        Date endAt = now.getTime();

        // 获取一天后的日期
        now.add(Calendar.DATE, +1);
        Date startAt = now.getTime();

        //可用于传值给job
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("jobDetail1","jobDetail1");
        JobDataMap jobDataMap2 = new JobDataMap();
        jobDataMap2.put("trigger1","这是jobDetail1的trigger");

        // 1、创建JobDetail实例,并与PrintWordsJob类绑定(Job执行内容)
        JobDetail jobDetail = JobBuilder.newJob(helloJob.class).usingJobData(jobDataMap)
                .withIdentity("job1", "group1").build();
        // 2、构建Trigger实例,每隔1s执行一次
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
                .usingJobData(jobDataMap2) //存值到jobDataMap
                
                .startAt(startAt) // 立即触发
                .endAt(endAt) // 表示该任务在一周后自动停止   ps:表示触发器结束触发的时间;
                //使用cron表达式    每天中午8点触发
                .withSchedule(CronScheduleBuilder.cronSchedule("0 0 8 * * ?"))
                .build();

        //3、执行
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
    }

    
    @RequestMapping("/deleteJob")
    public void deleteJob(String jobName,String jobGroup) throws SchedulerException
    {
        JobKey jobKey=new JobKey(jobName,jobGroup);
        scheduler.deleteJob(jobKey);
    }
    
    @RequestMapping("/pauseJob")
    public void pauseJob(String jobName,String jobGroup) throws SchedulerException
    {
        JobKey jobKey=new JobKey(jobName,jobGroup);
        scheduler.pauseJob(jobKey);
    }
    
    @RequestMapping("/resumeJob")
    public void resumeJob(String jobName,String jobGroup) throws SchedulerException
    {
        JobKey triggerKey=new JobKey(jobName,jobGroup);
        scheduler.resumeJob(triggerKey);
    }
    
    @RequestMapping("/clearAll")
    public void clearAll() throws SchedulerException {
        scheduler.clear();
    }

}

6.自定义工具类
package com.demo.quartz.utils;

import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

@Component
public class SchedulerUtils {

    // 调度器
    @Autowired
    private Scheduler scheduler;

    
    public void startJob(String cron,String jobName,String jobGroup,Class jobClass) throws SchedulerException
    {
        JobKey jobKey=new JobKey(jobName,jobGroup);
        //判断是否存在相同的计划任务
        if(!scheduler.checkExists(jobKey))
        {
            scheduleJob(cron,scheduler,jobName,jobGroup,jobClass);
        }
    }

    
    public void deleteJob(String jobName,String jobGroup) throws SchedulerException
    {
        JobKey jobKey=new JobKey(jobName,jobGroup);
        scheduler.deleteJob(jobKey);
    }
    
    public void pauseJob(String jobName,String jobGroup) throws SchedulerException
    {
        JobKey jobKey=new JobKey(jobName,jobGroup);
        scheduler.pauseJob(jobKey);
    }
    
    public void resumeJob(String jobName,String jobGroup) throws SchedulerException
    {
        JobKey triggerKey=new JobKey(jobName,jobGroup);
        scheduler.resumeJob(triggerKey);
    }
    
    public void clearAll() throws SchedulerException {
        scheduler.clear();
    }



    
    private void scheduleJob(String cron,Scheduler scheduler,String jobName,String jobGroup,Class jobClass) throws SchedulerException{
        
        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroup).build();
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).withSchedule(scheduleBuilder).build();
        scheduler.scheduleJob(jobDetail,cronTrigger);
    }

}

总结:
  1. 新建一个类实现Job并是实现void execute(JobExecutionContext var1) throws JobExecutionException;

  2. 创建JobDetail,封装Job,它是Scheduler(调度器)真正调度的对象,可以设置Job名称,组等信息,且名称不能重复

  3. 定义触发器Trigger,代表一个调度参数的配置,什么时候去调JobDetail,

  4. 创建就Scheduler,代表一个调度器 类似于Timer类。一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调用。

  5. 最后将jobDetail和 Trigger添加到Scheduler中,并启动

    scheduler.scheduleJob(jobDetail, trigger);
    scheduler.start();

代码已上到gitee: https://gitee.com/Lazy_001/quartz.git

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/396615.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号