「这是我参与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类里做了处理,下面我们来看下具体源码:
可以从类的注释上看到,这个的作用是:通过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类还是让我们省去了很多繁琐配置的,大大简化了开发。好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊