SpringBoot结合Quartz开发定时任务(一)

350 阅读2分钟

「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战

1、前言

由于笔者最近开发了一个向大屏定时发送数据的功能,使用到了定时任务,其实没开发过定时任务的话,还是有很多内容需要了解下的,下面就为大家分享下。定时任务顾名思义就是定时去触发执行的任务,常用的有Quartz、JDK自带的Timer、Spring Task、xxl-job这些,各有各的优缺点。笔者这里选用了Quartz,一方面是使用率很高,文档多、易上手,Quartz也是纯Java写的,调试起来也很方便。

2、前期准备

引入maven依赖,在pom文件中,增加如下内容:

<!-- 定时任务quartz -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

这里推荐大家使用以上形式引入,一方面好与SpringBoot的版本适配,另一方面是“开箱即用”,省去了很多繁琐的配置。笔者刚开始使用了org.quartz-scheduler下的包,需要额外进行配置,通过配置类将Scheduler添加到Spring的容器中。或者额外引入如下依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>5.3.10</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.3.10</version>
    <scope>compile</scope>
</dependency>

这里,笔者跟踪了下源码,发现是因为在spring-context-support包下的SchedulerFactoryBean类里做了处理,下面我们来看下具体源码:

7.png

可以从类的注释上看到,这个的作用是:通过FactoryBean工厂创建并配置一个有Spring容器管理的、可以作为依赖注入bean引用的Quartz调度器。下面为大家分析下主要源码:

//创建调度器实例,同时如果想自己实现的话,实现SchedulerFactory接口即可。
protected Scheduler createScheduler(SchedulerFactory schedulerFactory, @Nullable String schedulerName)
    throws SchedulerException {
​
    //重写当前线程的上下文 
    Thread currentThread = Thread.currentThread();
    ClassLoader threadContextClassLoader = currentThread.getContextClassLoader();
    boolean overrideClassLoader = (this.resourceLoader != null &&
                                   this.resourceLoader.getClassLoader() != threadContextClassLoader);
    if (overrideClassLoader) {
        currentThread.setContextClassLoader(this.resourceLoader.getClassLoader());
    }
    try {
        SchedulerRepository repository = SchedulerRepository.getInstance();
        //加锁,保证单例
        synchronized (repository) {
            Scheduler existingScheduler = (schedulerName != null ? repository.lookup(schedulerName) : null);
            Scheduler newScheduler = schedulerFactory.getScheduler();
            if (newScheduler == existingScheduler) {
                throw new IllegalStateException("Active Scheduler of name '" + schedulerName + "' already registered " +
                                                "in Quartz SchedulerRepository. Cannot create a new Spring-managed Scheduler of the same name!");
            }
            if (!this.exposeSchedulerInRepository) {
                //根据调度器名称删除Scheduler,保证单例
                SchedulerRepository.getInstance().remove(newScheduler.getSchedulerName());
            }
            return newScheduler;
        }
    }
    finally {
        if (overrideClassLoader) {
            // 重置初始线程的ClassLoader
            currentThread.setContextClassLoader(threadContextClassLoader);
        }
    }
}
​
​
//在bean工厂销毁时,销毁调度器,同时停止所有定时任务。
public void destroy() throws SchedulerException {
    if (this.scheduler != null) {
        logger.info("Shutting down Quartz Scheduler");
        this.scheduler.shutdown(this.waitForJobsToCompleteOnShutdown);
    }
}

当然还有其他的开启调度器、关闭调度器,配置Quartz等方法,这里九部委大家一一详述了,可以看到SchedulerFactoryBean类还是让我们省去了很多繁琐配置的,大大简化了开发。好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊