1. 概述
Spring 提供了一種便捷的方式來實現作業調度 API。 在我們部署多個應用程序實例時,它表現良好。
Spring 默認情況下無法處理多個實例之間的調度器同步。 相反,它會在每個節點上同時執行作業。
在本簡短教程中,我們將探討 ShedLock,這是一個 Java 庫,它確保在同一時間僅運行一次計劃任務,並且是 Quartz 的替代方案。
2. Maven 依賴
要使用 ShedLock 與 Spring 一起使用,我們需要添加 shedlock-spring 依賴項:
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>6.3.1</version>
</dependency>我們可以從 Maven 中央倉庫 獲取最新版本。
3. 配置
ShedLock 僅在具有共享數據庫的環境中有效,需要聲明合適的 LockProvider。
它會在數據庫中創建一個表或文檔,用於存儲當前鎖的信息。
目前,ShedLock 支持 Mongo、Couchbase、Elasticsearch、Redis、Hazelcast、ZooKeeper、Cassandra 以及任何具有 JDBC 驅動程序的系統。
對於本示例,我們將使用內存中的 H2 數據庫。
為了使其工作,我們需要提供 H2 數據庫 和 ShedLock JDBC 依賴項:
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>6.3.1</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.1.214</version>
</dependency>接下來,我們需要為 ShedLock 創建一個數據庫表,用於存儲調度器鎖的信息:
CREATE TABLE shedlock (
name VARCHAR(64),
lock_until TIMESTAMP(3) NULL,
locked_at TIMESTAMP(3) NULL,
locked_by VARCHAR(255),
PRIMARY KEY (name)
)我們應該在 Spring Boot 應用程序的屬性文件中聲明數據源,以便 DataSource bean 可以通過 Autowired 注入。
這裏,我們使用 application.yml 來定義 H2 數據庫的數據源:
spring:
datasource:
driverClassName: org.h2.Driver
url: jdbc:h2:mem:shedlock_DB;INIT=CREATE SCHEMA IF NOT EXISTS shedlock;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
username: sa
password:
讓我們配置 LockProvider,使用上面提供的數據庫配置。
Spring 可以使它變得非常簡單:
@Configuration
public class SchedulerConfiguration {
@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource);
}
}我們還需要提供以下配置要求:在我們的 Spring 配置類上添加 @EnableScheduling 和 @EnableSchedulerLock 註解:
@SpringBootApplication
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class SpringBootShedlockApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootShedlockApplication.class, args);
}
}defaultLockAtMostFor 參數指定在執行節點發生故障時鎖應保持的默認時間。它使用 ISO8601 持續時間 格式。
在下一部分,我們將看到如何覆蓋此默認值。
4. 創建任務
為了創建由 ShedLock 處理的計劃任務,我們只需在方法上添加 <em @Scheduled</em> 和 <em @SchedulerLock</em> 註解:
@Component
class BaeldungTaskScheduler {
@Scheduled(cron = "0 0/15 * * * ?")
@SchedulerLock(name = "TaskScheduler_scheduledTask",
lockAtLeastFor = "PT5M", lockAtMostFor = "PT14M")
public void scheduledTask() {
// ...
}
}首先,讓我們來看一下@Scheduled。它支持基於cron格式的表達式,其中該表達式表示“每15分鐘一次”。
接下來,讓我們看看@SchedulerLock,name參數必須唯一,而ClassName_methodName通常足以實現這一點。我們不想讓這個方法的運行超過一次,ShedLock使用唯一的名稱來實現這一點。
我們還添加了幾個可選參數。
首先,我們添加了lockAtLeastFor,以便在方法調用之間增加一些距離。使用“PT5M”表示該方法至少持有鎖5分鐘。換句話説,這意味着該方法最多由ShedLock每5分鐘運行一次。
接下來,我們添加了lockAtMostFor,用於指定在執行節點宕機時鎖應保持多久。使用“PT14M”表示鎖最多保持14分鐘。
在正常情況下,ShedLock在任務完成後直接釋放鎖。由於默認已在@EnableSchedulerLock中提供,因此我們不需要這樣做,但我們在這裏選擇覆蓋該默認值。
5. 結論
在本文中,我們學習瞭如何使用 ShedLock 創建和同步計劃任務。