Quartz Scheduler
Spring Boot 为使用 Quartz 调度器 提供了多项便利,包括 spring-boot-starter-quartz starter。如果 Quartz 可用,则会自动配置一个 Scheduler(通过 SchedulerFactoryBean 抽象)。
以下类型的 Bean 会被自动拾取并与 Scheduler 关联:
-
JobDetail:定义一个特定的 Job。JobDetail 实例可以通过 JobBuilder API 构建。
-
Trigger:定义某个特定 Job 何时被触发。
默认情况下,使用的是基于内存的 JobStore。然而,如果您的应用程序中存在一个 DataSource Bean,并且 spring.quartz.job-store-type 属性已按如下示例进行相应配置,则可以配置基于 JDBC 的存储:
- Properties
- YAML
spring.quartz.job-store-type=jdbc
spring:
quartz:
job-store-type: "jdbc"
当使用 JDBC store 时,可以在启动时初始化 schema,如下例所示:
- Properties
- YAML
spring.quartz.jdbc.initialize-schema=always
spring:
quartz:
jdbc:
initialize-schema: "always"
默认情况下,数据库会通过 Quartz 库提供的标准脚本进行检测和初始化。这些脚本会在每次重启时删除现有表,从而清除所有触发器。若要使用自定义脚本,请设置 spring.quartz.jdbc.schema 属性。某些标准脚本(例如用于 SQL Server、Azure SQL 和 Sybase 的脚本)在未经修改的情况下无法直接使用。在这种情况下,请复制该脚本并按照脚本注释中的说明进行编辑,然后将 spring.quartz.jdbc.schema 设置为使用您自定义的脚本。
要让 Quartz 使用不同于应用程序主 DataSource 的 DataSource,请声明一个 DataSource Bean,并在其 @Bean 方法上添加 @QuartzDataSource 注解。这样做可确保 Quartz 专用的 DataSource 同时被 SchedulerFactoryBean 和 schema 初始化所使用。
类似地,要让 Quartz 使用不同于应用程序主 TransactionManager 的 TransactionManager,请声明一个 TransactionManager Bean,并在其 @Bean 方法上添加 @QuartzTransactionManager 注解。
默认情况下,通过配置创建的作业不会覆盖从持久化作业存储中读取的已注册作业。要启用覆盖现有作业定义,请设置 spring.quartz.overwrite-existing-jobs 属性。
Quartz Scheduler 的配置可以通过 spring.quartz 属性和 SchedulerFactoryBeanCustomizer Bean 进行自定义,后者允许以编程方式对 SchedulerFactoryBean 进行定制。高级的 Quartz 配置属性可以通过 spring.quartz.properties.* 进行自定义。
特别地,一个 Executor bean 不会与调度器关联,因为 Quartz 提供了通过 spring.quartz.properties 配置调度器的方式。如果你需要自定义任务执行器,请考虑实现 SchedulerFactoryBeanCustomizer。
Job 可以定义 setter 方法来注入数据映射(data map)属性。普通 Bean 也可以通过类似的方式进行注入,如下例所示:
- Java
- Kotlin
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class MySampleJob extends QuartzJobBean {
// fields ...
private MyService myService;
private String name;
// Inject "MyService" bean
public void setMyService(MyService myService) {
this.myService = myService;
}
// Inject the "name" job data property
public void setName(String name) {
this.name = name;
}
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
this.myService.someMethod(context.getFireTime(), this.name);
}
}
import org.quartz.JobExecutionContext
import org.springframework.scheduling.quartz.QuartzJobBean
class MySampleJob : QuartzJobBean() {
// fields ...
private var myService: MyService? = null
private var name: String? = null
// Inject "MyService" bean
fun setMyService(myService: MyService?) {
this.myService = myService
}
// Inject the "name" job data property
fun setName(name: String?) {
this.name = name
}
override fun executeInternal(context: JobExecutionContext) {
myService!!.someMethod(context.fireTime, name)
}
}