很简单的quartz介绍

首先上下依赖
最好把log4j的依赖也添加进去,quartz需要打印日志,这里就不添加了.

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

贴一个最简单的实例

import com.anjiplus.job.Myjob1;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.Properties;

public class Test {
     
    public static void main(String[] args) throws Exception {
     
        Scheduler scheduler = getScheduler();
        JobDetail jobDetail = JobBuilder.newJob(Myjob1.class).build();
        scheduler.start();
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
                .startNow()
                .withSchedule(
                        SimpleScheduleBuilder.simpleSchedule()
                                .withIntervalInSeconds(1)
                                .repeatForever()
                )
                .build();
        scheduler.scheduleJob(jobDetail, trigger);
    }

    public static Scheduler getScheduler() throws Exception {
     
        Properties prop = new Properties();
        prop.load(Test.class.getResourceAsStream("/quartz.properties"));
        StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(prop);
        Scheduler scheduler = stdSchedulerFactory.getScheduler();
        return scheduler;
    }
}
//
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;

public class Myjob1 implements  Job {
     
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
     
        System.out.println(new Date()+" myJob1");
    }
}

打印结果:
Mon Aug 03 15:58:43 CST 2020 myJob1
Mon Aug 03 15:58:44 CST 2020 myJob1
Mon Aug 03 15:58:45 CST 2020 myJob1
Mon Aug 03 15:58:46 CST 2020 myJob1
Mon Aug 03 15:58:47 CST 2020 myJob1
Mon Aug 03 15:58:48 CST 2020 myJob1

以上是最简单的一个quartz调度.

一 quartz重要组件:

1 Scheduer

Scheduler是全局调度,通过将JobDetail与Trigger添加到其中,用来监控任务的执行,所以他是最主要的.
Scheduer的获取是通过SchedulerFactory来获取的,SchedulerFactory是个接口,其有两个实现类:StdSchedulerFactory和DirectSchedulerFactory,他们两个的区别是DirectSchedulerFactory是硬编码,需要把配置写在代码之中,一般不会采用这个类来获取Scheduler,所以直接记住StdSchedulerFactory就好,上述例子中,传入一个quartz.properties就是读取配置文件.(配置文件稍后再说)
Scheduer需要调用.start()方法才会真正地调度job执行,通过shutdown()方法去销毁,并且可以随时增加和删除Job,但只有start()后任务才会真正被调度.

2 JobDetail与Job

Job是一个接口,继承Job接口后实现excute方法,在exceute方法中书写Job执 行逻辑.
JobDetail 负责job的实例化,它代表着Job的多次执行,而job代表着每次启动都是需要一个job的实例,比如说一个job要运行N次,JobDetail代表着N次,而Job代表着一次.
JobDetail中有job的属性,其中很重要的是JobDataMap,它是JobDetail与Job通信的关键,可以设置JobDataMap是否每一次都更新,比如说在调度之前,JobDetail中添加JobDataMap中"count"’->0 来统计job执行次数,这样每次执行的job都可以获取JobDataMap中的count,是允许运行的job更改count值,并保存,还是不允许呢,既然是统计job执行次数,当然是允许更改了,每次都把count变量加1,不然的话每次获取的count都是0.至于如何设置,后面再说.

3 Trigger

上面定义任务运行的是JobDetail和Job,但是何时运行就是Trigger
Trigger是个接口有四个子接口
CronTrigger
SimpleTrigger
DailyTimeIntervalTrigger
CalendarIntervalTrigger
以上的类我们不需要关心,因为quartz通过建造者模式,传入SchdulerBuiler来决定到底是哪种类型的Trigger.稍后说如何创建Trigger

二 组件API

上面对重要组件有了一定的认识,下面通过重要Api继续说明:

1 Scheduer

        /*读取配置文件并根据配置文件创建Scheduler*/
        Properties prop = new Properties();
        prop.load(Test.class.getResourceAsStream("/quartz.properties"));
        StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(prop);
        Scheduler scheduler = stdSchedulerFactory.getScheduler();
        /*绑定JobDetail按照Trigger定义的计划去执行*/
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
        //scheduler.shutdown();

上面代码就是创建Scheduler.quartz.properties放在了resources目录下.配置文件中的配置要最后说,里面内容比较多.

2 JobDetail与Job

JobDetail的创建:

          JobDetail jobDetail = JobBuilder
                /*传递我们的Job*/
                .newJob(Myjob1.class)
                .withIdentity("myjob")
                /*意外中止,将会在重启时,先补充前面未执行的批次*/
                //.requestRecovery(true)
                /*设置obDataMap中的值,也可以通过JobDetail.getJobDataMap.put(k,v)来设置*/
                .usingJobData("count",0)
                .build();

Job创建:

@DisallowConcurrentExecution
@PersistJobDataAfterExecution
//继承Job类
public class Myjob implements  Job {
     
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
     
        try {
     
            //可以获取到JobDetail
            JobDetail jobDetail = context.getJobDetail();
            //JobDataMap
            JobDataMap jobDataMap = jobDetail.getJobDataMap();
            int count = (Integer) jobDataMap.get("count") + 1;
            jobDataMap.put("count",count);
            System.out.println("myjob的第"+count+"次执行");
            
            //你要执行的逻辑写在这里
            
        } catch (Exception e) {
     
                  /*如果想要让job抛出异常被Scheduler捕获,就必须是JobExecutionException异常,
            并且下面告诉了Schduler应该接下怎么怎么做*/
            JobExecutionException jobE = new JobExecutionException(e.getMessage());
            /*立即重新执行*/
            //jobE.refireImmediately();
            /*立即取消所有与这个Job关联的trigger*/
            //jobE.setUnscheduleAllTriggers(true);
            /*如果不做任何处理,下次调度正常执行,就不需要设置任何内容,直接抛出*/
            throw jobE;
        } finally {
     
        }
    }
}

@DisallowConcurrentExecution
job是否允许并发,比如定义一个每秒中执行一次的job,如果上一个job没有执行完,是否允许下一个job执行,这个注解是不允许.
@PersistJobDataAfterExecution
job执行中,可以更新JobDataMap,每次拿到的JobDataMap都是上个job更新后的结果.因为上述JobDetail中初始化了一个"count"变量,所以上述代码执行结果就是

myjob的第1次执行
myjob的第2次执行
myjob的第3次执行

如果没有这个注解
myjob的第1次执行
myjob的第1次执行
myjob的第1次执行

excute方法中只有抛出JobExecutionException才能被Shecduler捕获,抛出其他异常,Scheduler将不会做任何处理.

3 Trigger

上面说了Tigger有四个实现类,但是这里只说两个,因为这两个基本就可以满足我们的定时了.
1) SimpleTrigger

SimpleTrigger trigger = TriggerBuilder
                .newTrigger()
                .startNow()
                /*指定trigger的开始-结束时间*/
                //.startAt(new Date())
                //.endAt(new Date())
                /*trigger的优先级任意整数,默认5
                同时出发的trigger优先级越高越先执行*/
                //.withPriority(5)
                /*跳过某些时间下面会说*/
                //.modifiedByCalendar("myCalendar")
                .withIdentity("trigger1", "group1")
                .withSchedule(
                 //通过这里的Scheduler来确定的build()之后具体得到的是什么Trigger
                       SimpleScheduleBuilder.simpleSchedule()
                                /*job间隔时间*/
                                .withIntervalInSeconds(1)
                                /*job执行几次*/
                                //.withRepeatCount(1)
                                .repeatForever()
                )
                .build();

2) CronTrigger

                   .withSchedule(
                 //通过这里的Scheduler来确定的build()之后具体得到的是什么Trigger           
                        CronScheduleBuilder.cronSchedule("*/1 * * * * *")
                       /*设置时区,默认是运行server的时区*/
                        //.inTimeZone()
                  )
                 .build();

CronTrigger就是基于con表达式去执行,基本可以满足无限循环的job
SimpleTrigger就是简单的执行几次,每一次的间隔
在上方SimpleTrigger代码中有一个.modifiedByCalendar(“myCalendar”)方法,这里设置的是一个排除的日期,这里的"myCalendar"是添加到Scheduler中的,trigger引用就通过name引用

        HolidayCalendar myCalendar= new HolidayCalendar();
        //添加配出时间
        myCalendar.addExcludedDate(Date1);
        myCalendar.addExcludedDate( Date2 );
        scheduler.addCalendar("myCalendar", myCalendar, false,true);

Calendar是一个接口里面很多实现类,可以自己去查看.
另外还有一个是Misfire机制,它是作用在持久化的任务上的,如果因为trigger线程问题(任务过多,有些tigger没有在合适时间执行),或者意外宕机等导致的任务没有执行,需要补上任务的,可以查看misfire机制.

4 配置文件

quartz.properties

# 固定前缀org.quartz
# 主要分为scheduler、threadPool、jobStore、plugin等部分
# 实例化ThreadPool时,使用的线程类为SimpleThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.scheduler.instanceName = myquartz
# threadCount和threadPriority将以setter的形式注入ThreadPool实例
# 并发个数
org.quartz.threadPool.threadCount = 300
# 优先级
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
org.quartz.jobStore.misfireThreshold = 5000

# 默认存储在内存中
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
#持久化
#org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#org.quartz.jobStore.tablePrefix = QRTZ_
#org.quartz.jobStore.dataSource = qzDS
#org.quartz.dataSource.qzDS.driver = com.mysql.cj.jdbc.Driver
#org.quartz.dataSource.qzDS.URL = jdbc:mysql://ip:port/库名?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
#org.quartz.dataSource.qzDS.user = dev
#org.quartz.dataSource.qzDS.password = dev
#org.quartz.dataSource.qzDS.maxConnections = 10
#org.quartz.dataSource.qzDS.connectionProvider.class=xxxx

org.quartz.jobStore.class 是非常重要的一个参数,有三个可选值,RAMJobStore,JobStoreTX,TerracottaJobStore
TerracottaJobStore是用于集群
RAMJobStore是使用内存保存job信息(使用最多)
JobStoreTX是使用数据库去保存信息,但是需要提前建表,需要的话建表语句官网查.(使用其次多)

了解以上内容后基本的开发中的job就可以满足需求了,还需要一些没有介绍的功能请查看官网
quartz官网2.3.0

你可能感兴趣的:(java,quartz,java)