Quartz学习整理

Quartz学习整理

2023今天学习的内容是石英钟Quartz定时启动任务的框架

应用场景

618淘宝的0:00秒杀
qq新闻的定时推送
未支付的订单,到时间删除订单
到了指定的时间就执行相应的任务,都需要Quartz框架

Quartz的体系架构

1.任务类

实现Job类,重写execute()方法

2.触发器Trigger

定义时间规则CronTrigger,

3.调度器Schduler

将任务和出发器绑定,调度器会在符合时间规则的条件下,执行任务

Quartz的简单使用

1.新建maven项目

2.pom.xml添加依赖

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--Quartz任务调度-->
        <!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.3</version>
        </dependency>
    </dependencies>

3.application.yml文件配置文件

server:
  port: 8081
spring:
  application:
    name: QUARTZSERVER

4.项目启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

5.任务类

import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class FirstJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        //编写要执行的任务即可
        //当到达设定的时间后,Quartz就会自动调用此execute方法
        //可以通过JobExecutionContext类型的参数,来获取任务的相关信息
        //【说明】在企业级项目中,定时任务有很多,为了区分任务,可以给任务分组,设置任务的名字
        JobDetail jobDetail=context.getJobDetail();
        //jobDetail.getKey().getGroup()  
        //getKey() 先获取任务  
        //getGroup() 获取组   字符串类型,代表组的名字
        System.out.println("任务所在的组:"+jobDetail.getKey().getGroup());
        //getName()  获取的是任务的名字
        System.out.println("任务的名字是:"+jobDetail.getKey().getName());
        for (int i=1; i<=10; i++){
            System.out.println("i="+i);
        }
    }
}

6.触发器Trigger

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.stereotype.Service;

import java.util.GregorianCalendar;

@Service
public class JobServiceImpl implements JobService {
    @Override
    public String startJob1() {
        String result="";
        //声明时间规则
        //1、声明触发器
        Trigger trigger= TriggerBuilder.newTrigger()
                //参数1:触发器的名字
                //参数2:触发器所在的组的名字
                .withIdentity("trigger1","triggerGroup1")
                .startNow() //执行后,触发器立刻开始生效,还可以设置具体的开始时间 startAt(通过GregorianCalendar设置开始时间)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                    .withIntervalInSeconds(3)  //每间隔多长时间执行一次任务
                    .repeatForever()  //重复的次数:repeatForever()---一直重复   withRepeatCount(重复的次数)
                ).endAt(new GregorianCalendar(2023,6,19,11,0,0).getTime())
                .build();
        //bug:结束时间到达后,并不能结束

        //2、把要执行的任务 封装在JobDetail中
        JobDetail jobDetail= JobBuilder.newJob(FirstJob.class)
                .withIdentity("job1","group1")
                .build();

        //3、声明调度器Scheduler:把触发器和任务绑定在一起
        try {
            Scheduler scheduler= StdSchedulerFactory.getDefaultScheduler();

            //绑定触发器和任务
            scheduler.scheduleJob(jobDetail,trigger);

            //调度器开始调度
            scheduler.start();

            result="第一个任务已经成功开启";
        } catch (SchedulerException e) {
            result="第一个任务开启失败!";
            e.printStackTrace();
        }

        return result;
    }
}

[扩展]使用线程池来优化线程的使用

原因:线程的创建和销毁,增加线程的开销,降低了线程的使用效率,
需要线程池来固定线程的数量,防止无限的消耗,最终耗尽系统资源

1、在resources下新建quartz.properties配置文件

​ quartz在启动的时候,默认就会读取的配置文件

2、在此文件中配置线程池信息

# 指定调度器的类型
org.quartz.scheduler.instanceName=DefaultQuartzScheduler

 # 指定线程池的类型
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool

 # 线程池中线程的数量
org.quartz.threadPool.threadCount=10

 # 线程池中线程的优先级
org.quartz.threadPool.threadPriority=5

#非持久化Job ,对执行的任务不进行持久化存储
org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore

触发器Tigger的类型

触发器是用来规定任务的执行时间
1 SimpleTrigger简单时间规则(了解即可)
2 CronTrigger,使用Cron表达式来声明时间规则,从而触发不同的时间场景
6,7位组成,位与位之间用 空格 隔开,分别代表
秒 分 时 日 月 星期 年

各个位置上允许出现的值
各个位置上允许出现的值
3、各个位置上的字符含义

* 可以出现在任意位置上,表示:每一XXX

* * * 20 6 ? 2023

, 表示的是列表,当某个位置上出现多个值的时候,值之间使用,进行分割

10,30 * * 20 6 ? 2023 23年6月20日的每个小时的每分钟的第10秒、30秒的时候分别执行任务

- 表示的范围,是连续的一个区间

0-9 * * 20 6 ? 2023 23哪年6月20日的每个小时的每分钟的第0 1 2 3 4 5 6 7 8 9秒时分别执行任务

0,1,2,3,4,5,6,7,8,9 * * 20 6 ? 2023

/ 步长 每增加多少 每间隔多少

0/5 5/3 * 20 6 ? 2023

? 只能出现在 日期和星期的位置上,当设置了日期或星期中的任意一个值,另一个就可以使用?,表示任意值
在这里插入图片描述
星期的取值范围1-7 1表示的是星期日, 2 表示星期1 7对应星期六

L :只能出现在星期、日期的位置上

​ 出现日期的位置上,表示当月的最后一天,自行判断平、润年 及大小月份

​ 出现在星期的位置上: 表示这个星期的最后一天, 指的是周六 7

​ * * * ? 6 L 2023

​ 出现在星期的位置上:L的前面出现了1-7之间的数字,表示 最后一个星期几

​ 0 30 17 ? * 6L 每个月的最后一个星期五的17:30:00执行任务

W:只能出现在日期位置上,表示离该日期最近的一个工作日

​ 0 0 8 17W 6 ? 2023 23年6月16日 8:00:00执行任务

【说明】规则不能跨月,只能在本月内计算

​ 0 0 8 1W 7 ? 2023 23年7月3日的8:00:00执行,而不是 23年6月30日的8:00:00,因为跨到6月份

LW 只能出现在日期里,表示当月的最后一个工作日

# 该字符只用在星期字段中,"4#2"代表第二个星期3,“5#4”代表第4个星期四

语法 :星期值#第几个
应用CronTrigger来声明时间规则

@Override
public String startJob2() {
    String result="";
    //声明CronTrigger
    Trigger trigger=TriggerBuilder.newTrigger()
            .withIdentity("trigger2","triggerGroup1")
            .withSchedule(CronScheduleBuilder.cronSchedule("3/5 * 15 19 6 ?"))
            .build();

    JobDetail jobDetail=JobBuilder.newJob(FirstJob.class)
            .withIdentity("job2","group1")
            .build();

    try {
        Scheduler scheduler=StdSchedulerFactory.getDefaultScheduler();

        scheduler.scheduleJob(jobDetail,trigger);

        scheduler.start();

        result="任务2被启动!";
    } catch (SchedulerException e) {
        result="任务2启动失败!";
        e.printStackTrace();
    }
    return result;
}

任务的控制

@Override
//任务的暂停
public String pauseJob(String name, String goup) {
    String result="";
    //1、先获取调度器
    try {
        Scheduler scheduler=StdSchedulerFactory.getDefaultScheduler();
        //2、通过调度器来暂定任务
        scheduler.pauseJob(JobKey.jobKey(name,goup));
        result="任务"+name+"已经被暂停";
    } catch (SchedulerException e) {
        result="任务"+name+"暂停失败!";
        e.printStackTrace();
    }

    return result;
}

@Override
//任务的恢复
public String resumeJob(String name, String group) {
    String result="";
    try {
        Scheduler scheduler=StdSchedulerFactory.getDefaultScheduler();
        scheduler.resumeJob(JobKey.jobKey(name, group));
        result="任务"+name+"已经被恢复执行";
    } catch (SchedulerException e) {
        result="任务"+name+"恢复失败!";
        e.printStackTrace();
    }
    return result;
}

删除单个任务

@Override
public String deleteJob(String name, String group) {
    String result="";
    try {
        Scheduler scheduler=StdSchedulerFactory.getDefaultScheduler();
        boolean boolResult= scheduler.deleteJob(JobKey.jobKey(name, group));
        if(boolResult){
            result="删除任务"+name+"成功!";
        }else{
            result="删除任务"+name+"失败!";
        }
    } catch (SchedulerException e) {
        result="删除任务"+name+"失败!";
        e.printStackTrace();
    }
    return result;
}

任务的批量暂停、恢复

【注意】批量操作是通过组进行操作,把组名封装在GroupMatcher中

@Override
public String pauseJobs(String group) {
    String result="";
    try {
        Scheduler scheduler=StdSchedulerFactory.getDefaultScheduler();
        //把组信息封装在了GroupMatcher中
        GroupMatcher<JobKey> groupMatcher=GroupMatcher.groupEquals(group);
        scheduler.pauseJobs(groupMatcher);
        result="组"+group+"批量暂停成功";
    } catch (SchedulerException e) {
        result="组"+group+"批量暂停失败";
        e.printStackTrace();
    }
    return result;
}

@Override
public String resumeJobs(String group) {
    String result="";
    try {
        Scheduler scheduler=StdSchedulerFactory.getDefaultScheduler();
        //把组信息封装在了GroupMatcher中
        GroupMatcher<JobKey> groupMatcher=GroupMatcher.groupEquals(group);
        scheduler.resumeJobs(groupMatcher);
        result="组"+group+"批量恢复成功";
    } catch (SchedulerException e) {
        result="组"+group+"批量恢复失败";
        e.printStackTrace();
    }
    return result;
}

在控制器中调用业务逻辑

@RestController
public class JobController {
    @Autowired
    private Job1Service job1Service;

    @GetMapping("/start1")
    public String start1(){
        return job1Service.startJob();
    }
    @GetMapping("/start2")
    public String start2(){
        return job1Service.startJob2();
    }
    @GetMapping("/pause")
    public String pause(String name,String group){
        return job1Service.pauseJob(name,group);
    }
    @GetMapping("/resume")
    public String resume(String name,String group){
        return job1Service.pauseJob(name,group);
    }
    @GetMapping("/delete")
    public String delete(String name,String group){
        return job1Service.deleteJob(name,group);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值