01.Quartz 环境搭建-基于内存

别等时光非礼了梦想. 提交于 2019-11-28 18:18:43

quartz 是java 领域中应用最广泛的一个定时任务调度框架, 支持两种存储方式:基于内存存储和基于数据库存储. 同城在企业开发中都是结合spring使用, 直接按指定规则配置即可. 但是笔者认为, 要想对quartz 有个相对比较深入的了解, 还是应该搭建一个JavaSE 环境来进行学习和测试. quartz 的开发流程:

  1. 创建调度器工厂
  2. 加载配置文件(如果使用默认配置文件名, 则可以省略)
  3. 获取调度器
  4. 创建定时任务
  5. 创建触发器(可以是SimpleTrigger 和 CronTrigger)
  6. 将定时任务添加到调度器中
  7. 启动调度器

1. 项目搭建

笔者习惯于使用maven 开发项目, 因此首先创建一个maven 项目.

1.1 引入maven 依赖

  • quartz 只需要引入一个核心依赖 quartz 即可.
  • quartz 默认使用slf4j 输出日志, 但是笔者习惯于使用logback, 因此直接替换了logback 的包.
  • 笔者使用junit 单元测试进行测试
<!-- 相关版本号 -->
<properties>
    <quartz.version>2.2.3</quartz.version>
    <slf4j.api.version>1.7.25</slf4j.api.version>
    <logback.version>1.2.3</logback.version>
    <junit.version>4.12</junit.version>
</properties>

<!-- 相关依赖 -->
<dependencies>
    <!-- 引入quartz 核心包 -->
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>${quartz.version}</version>
    </dependency>

    <!-- 集成日志环境 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.api.version}</version>
    </dependency>

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>${logback.version}</version>
    </dependency>

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>${logback.version}</version>
    </dependency>

    <!-- 添加单元测试依赖 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
    </dependency>
</dependencies>

1.2 创建quartz 配置文件

  • quartz 默认加载类路径下的quartz.propeties 文件作为quartz 的配置文件, 此文件中可以自定义quartz的一些运行参数.
  • 默认情况下如果找不到quartz.preoperties文件, quartz 会加载自身jar保重的配置文件. 不过笔者还是推荐使用自定义的配置文件.
  • 配置文件的默认名称为quartz.properties,不过可以修改. 笔者修改为quartz-ram.properties.

quartz-ram.properties

# 调度器实例名称
org.quartz.scheduler.instanceName = quartz-scheduler-ram
# 定时任务信息存储方式: 内存
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
# 定时任务线程数
org.quartz.threadPool.threadCount = 3

1.3 创建日志配置文件

logback 需要在类路径下创建logback.xml配置文件.

logback.xml

<?xml version="1.0"?>
<configuration debug="false">

    <!-- 应用名称 -->
    <contextName>learn-quartz</contextName>

    <!-- 输出到控制台 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- 定义日志输出格式 -->
            <pattern>[%d{yyyy-MM-dd HH:mm:ss:SSS}][%thread][%thread][%-5level][%logger{36}]-%msg%n</pattern>
        </encoder>
    </appender>

    <!-- 配置根logger -->
    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

2. 开发定时任务

2.1 创建定时任务类

quartz 规定每一个要执行的定时任务都需要继承org.quartz.Job 接口, 病实现execute 方法. 当定时任务触发时, quartz 会新实例化一个Job实例, 然后调用其execute 方法.

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Trigger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

public class HelloJob implements Job {

    private static Logger logger = LoggerFactory.getLogger(HelloJob.class);

    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        Trigger trigger = jobExecutionContext.getTrigger();

        logger.info("hello,quartz! this:{}, job:{}, trigger:{}, preFire:{}, nextFire:{},",
                this,jobExecutionContext.getJobDetail().getKey(), trigger.getKey(),
                toString(trigger.getPreviousFireTime()), toString(trigger.getNextFireTime()));
    }

    // 格式化日期
    private String toString(Date date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        return simpleDateFormat.format(date);
    }
}

2.2 创建测试类

quartz的触发器有两种, 一种是SimpleTrigger, 用于触发重复1次或以固定时间重复N次的定时任务; 另一种是CronTrigger, 用于触发按日历来执行的定时任务. 笔者针对于这两种触发器, 写了两个入门demo.

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.zongf.learn.quartz.l01.job.HelloJob;

/**
 * @Description: 测试环境集成
 * @author: zongf
 * @date: 2019-03-27 10:58
 */
public class Test01 {

    private SchedulerFactory schedulerFactory;

    private Scheduler scheduler;

    // 测试用例启动时, 初始化调度工厂和调度器
    @Before
    public void setUp() throws SchedulerException {
        // 1. 创建调度工厂
        schedulerFactory = new StdSchedulerFactory();

        // 2. 默认加载类路径下quartz.properties配置文件, 笔者指定配置文件
        ((StdSchedulerFactory) schedulerFactory).initialize("quartz-ram.properties");

        // 3. 获取调度器
        scheduler = schedulerFactory.getScheduler();
    }

    // 测试用例完成时, 线程休眠, 否则进行就直接结束了
    @After
    public void tearDown() throws InterruptedException {
        Thread.sleep(Integer.MAX_VALUE);
    }

    // 测试简单触发器
    @Test
    public void scheduSimpleTrigger() throws SchedulerException {

        // 4. 创建定时任务
        JobDetail job = JobBuilder.newJob(HelloJob.class)
                .withIdentity("myJob", "group1")
                .build();

        // 5. 创建简单触发器
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("myTrigger", "group1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(3)
                        .repeatForever())
                .build();

        // 6. 将定时任务添加到调度队列中
        scheduler.scheduleJob(job, trigger);

        // 7. 启动调度器
        scheduler.start();
    }

    // 测试cron 触发器
    @Test
    public void test_CronTrigger() throws SchedulerException {
        // 4. 创建定时任务
        JobDetail job = JobBuilder.newJob(HelloJob.class)
                .withIdentity("myJob", "group1")
                .build();

        // 6. 创建cron触发器, 每5秒执行一次
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("myTrigger", "group1")
                .startNow()
                .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?"))
                .build();

        // 7. 将定时任务添加到调度队列中
        scheduler.scheduleJob(job, trigger);

        // 8. 启动调度器
        scheduler.start();
    }
}

2.3 测试输出结果

从控制台输出可以看出, 每次执行的job实例都不相同, 这一点是很重要的.

[2019-03-28 17:06:10:645]-hello,quartz! this:org.zongf.learn.quartz.l01.job.HelloJob@b25e99f, job:group1.myJob, trigger:group1.myTrigger, preFire:2019-03-28 17:06:10.000, nextFire:2019-03-28 17:06:15.000,
[2019-03-28 17:06:15:003]-hello,quartz! this:org.zongf.learn.quartz.l01.job.HelloJob@6d5a007, job:group1.myJob, trigger:group1.myTrigger, preFire:2019-03-28 17:06:15.000, nextFire:2019-03-28 17:06:20.000,
[2019-03-28 17:06:20:002]-hello,quartz! this:org.zongf.learn.quartz.l01.job.HelloJob@1e9e39a8, job:group1.myJob, trigger:group1.myTrigger, preFire:2019-03-28 17:06:20.000, nextFire:2019-03-28 17:06:25.000,
[2019-03-28 17:06:25:003]-hello,quartz! this:org.zongf.learn.quartz.l01.job.HelloJob@2e0899d0, job:group1.myJob, trigger:group1.myTrigger, preFire:2019-03-28 17:06:25.000, nextFire:2019-03-28 17:06:30.000,

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!