quartz

  1. 简介
  2. 快速开始
  3. 自定义 Job 任务
  4. 任务数据存储
  5. cron 表达式
  6. Trigger 传参

简介

quartz,一个定时任务框架,比较简单。

快速开始

  1. 依赖关系

    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.3.2</version>
        <exclusions>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <!--测试demo是idk8如果是更高版本则这里可以用新版本 -->
        <version>1.2.7</version>
    </dependency>
    
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.5.2</version>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.22</version>
    </dependency>
    
  2. quartz.properties

    # 实例名称
    org.quartz.scheduler.instanceName=MyScheduler
    # 并发数
    org.quartz.threadPool.threadCount=3
    # 基于内存作为定时触发器
    org.quartz.jobstore.class =org.quartz.simpl.RAMJobstore
    
  3. logback.xml

    <configuration>
    
        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss} - %magenta([%thread]) %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern>
            </encoder>
        </appender>
    
        <root level="debug">
            <appender-ref ref="CONSOLE" />
        </root>
    
    </configuration>
    
  4. QuartzTest

    public class QuartzTest {
    
        @Test
        public void test01() throws SchedulerException {
            // 工厂模式获取定时器管理类,可以管理触发器 Triggers 和任务类 Job
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            scheduler.start();
            scheduler.shutdown();
        }
    }
    

    执行打印日志,表示成功

自定义 Job 任务

  1. 自定义 Job,实现接口 org.quartz.Job

    @Slf4j
    public class CustomJob implements Job {
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            log.info(String.format("任务执行…… %s", new Date()));
        }
    }
    
  2. 开启 job

    @Test
    public void test01() throws SchedulerException, InterruptedException {
        // 工厂模式获取定时器管理类,可以管理触发器 Triggers 和任务类 Job
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
    
        // 创建 Job 执行
        JobDetail detail = JobBuilder.newJob(CustomJob.class).build();
    
        // 创建一个 Trigger 触发器,立刻执行,设置其执行方式为每隔三秒执行一次,一直执行
        SimpleTrigger trigger = TriggerBuilder
            .newTrigger()
            .startNow()
            .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).repeatForever())
            .build();
    
        // 执行。开始定时器
        scheduler.scheduleJob(detail, trigger);
        scheduler.start();
    
        // 让主线程沉睡,同时观测定时器触发效果
        TimeUnit.MINUTES.sleep(10000);
        scheduler.shutdown();
    }
    
    // 创建一个 Trigger 触发器
    // 除了 startNow 之外,还可以指定开始和结束时间,还可以指定表达式
    // 除了一直执行之外,还可以执行执行次数 withRepeatCount
    SimpleTrigger trigger = TriggerBuilder
        .newTrigger()
        .startAt(start_time)
        .endAt(end_time)
        .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).withRepeatCount(5))
        .build();
    

任务数据存储

  1. 自定义 Job

    @Slf4j
    // 可以在数据调度传递过程中修改数值
    @PersistJobDataAfterExecution
    public class CustomJob implements Job {
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
    
            String username = jobDataMap.get("username").toString();
            log.info(String.format("username -> %s", username));
    
            Integer age = (Integer) jobDataMap.get("age");
            log.info(String.format("age -> %s", age));
    
            // 替换数据
            jobDataMap.put("age", ++age);
        }
    }
    
  2. 定时器调度

    @Test
    public void test02() throws SchedulerException, InterruptedException {
        // 工厂模式获取定时器管理类,可以管理触发器 Triggers 和任务类 Job
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
    
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("age", 10);
    
        // 创建 Job 执行
        JobDetail detail = JobBuilder
            .newJob(CustomMapJob.class)
            // 在定时任务执行过程中传递数据
            .usingJobData("username", "zhangsan")
            .usingJobData(jobDataMap)
            .build();
    
        // 创建一个 Trigger 触发器,立刻执行,设置其执行方式为每隔三秒执行一次,一直执行
        SimpleTrigger trigger = TriggerBuilder
            .newTrigger()
            .startNow()
            .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).repeatForever())
            .build();
    
        // 执行。开始定时器
        scheduler.scheduleJob(detail, trigger);
        scheduler.start();
    
        // 让主线程沉睡,同时观测定时器触发效果
        TimeUnit.MINUTES.sleep(10000);
        scheduler.shutdown();
    }
    

cron 表达式

如果想要实现一些复杂操作,那么需要使用 cron 表达式

字段名 允许的值 允许的通配符
0 ~ 59 , - * /
0 ~ 59 , - * /
0 ~ 23 , - * /
1 ~ 31 , - * ? / L W C
1 ~ 12 or JAN ~ DEC , - * /
周几 1 ~ 7 or SUN ~ SAT , - * ? / L C #
年(可选字段) empty 1970 ~2099 , - * /

cron 用于配置 cronTrigger 实例,可以直接到网络上查找一些在线表达式生成工具直接生成

@Test
public void test04() throws SchedulerException, InterruptedException {
    // 工厂模式获取定时器管理类,可以管理触发器 Triggers 和任务类 Job
    Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

    // 创建 Job 执行
    JobDetail detail = JobBuilder.newJob(CustomJob.class).build();

    Calendar calendar = Calendar.getInstance();
    Date start_time = calendar.getTime();
    calendar.add(Calendar.SECOND, 10);
    Date end_time = calendar.getTime();

    CronTrigger trigger = TriggerBuilder
        .newTrigger()
        .startNow()
        .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
        .build();

    // 执行。开始定时器
    scheduler.scheduleJob(detail, trigger);
    scheduler.start();

    // 让主线程沉睡,同时观测定时器触发效果
    TimeUnit.MINUTES.sleep(10000);
    scheduler.shutdown();
}

Trigger 传参

注意,trigger 虽然也可以进行传递参数,但是 trigger 中的数据不会发生变化,哪怕使用注解 @PersistJobDataAfterExecution 也一样

  1. Job

    @Slf4j
    // 可以在数据调度传递过程中修改数值
    @PersistJobDataAfterExecution
    public class CustomTriggerMapJob implements Job {
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            JobDataMap jobDataMap = jobExecutionContext.getTrigger().getJobDataMap();
            String value = jobDataMap.get("trigger").toString();
            log.info(String.format("trigger: %s", value));
        }
    }
    
  2. 定时器调度

    @Test
    public void test05() throws SchedulerException, InterruptedException {
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
    
        JobDetail detail = JobBuilder.newJob(CustomTriggerMapJob.class).build();
    
        CronTrigger trigger = TriggerBuilder
            .newTrigger()
            .startNow()
            .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
            .build();
    
        // 除了在 detail 中传递参数之外,还可以在 trigger 传递参数
        trigger.getJobDataMap().put("trigger", "value");
    
        scheduler.scheduleJob(detail, trigger);
        scheduler.start();
    
        TimeUnit.MINUTES.sleep(10000);
        scheduler.shutdown();
    }
    

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。