1. Overview
1.概述
Spring provides an easy way to implement API for scheduling jobs. It works great until we deploy multiple instances of our application.
Spring提供了一种简单的方法来实现调度作业的API。在我们部署应用程序的多个实例之前,它的效果很好。
Spring, by default, cannot handle scheduler synchronization over multiple instances. It executes the jobs simultaneously on every node instead.
默认情况下,Spring不能处理多个实例的调度器同步。它在每个节点上同时执行作业。
In this short tutorial, we’ll look at ShedLock — a Java library that makes sure our scheduled tasks run only once at the same time and is an alternative to Quartz.
在这个简短的教程中,我们将看看ShedLock–一个确保我们的计划任务在同一时间只运行一次的Java库,是Quartz的替代品。
2. Maven Dependencies
2.Maven的依赖性
To use ShedLock with Spring, we need to add the shedlock-spring dependency:
要在Spring中使用ShedLock,我们需要添加 the shedlock-spring dependency。
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>2.2.0</version>
</dependency>
3. Configuration
3.配置
Note that ShedLock works only in environments with a shared database by declaring a proper LockProvider. It creates a table or document in the database where it stores the information about the current locks.
注意,ShedLock只在有共享数据库的环境中通过声明一个适当的LockProvider来工作。它在数据库中创建一个表或文档,在那里存储关于当前锁的信息。
Currently, ShedLock supports Mongo, Redis, Hazelcast, ZooKeeper and anything with a JDBC driver.
目前,ShedLock支持Mongo、Redis、Hazelcast、ZooKeeper和任何带有JDBC驱动的软件。
For this example, we’ll use an in-memory H2 database.
在这个例子中,我们将使用内存中的H2数据库。
To make it work, we need to provide the H2 database and the ShedLock JDBC dependency:
为了使其发挥作用,我们需要提供H2数据库和ShedLock JDBC依赖性。
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.200</version>
</dependency>
Next, we need to create a database table for ShedLock to keep information about scheduler locks:
接下来,我们需要为ShedLock创建一个数据库表,以保存关于调度器锁的信息。
CREATE TABLE shedlock (
name VARCHAR(64),
lock_until TIMESTAMP(3) NULL,
locked_at TIMESTAMP(3) NULL,
locked_by VARCHAR(255),
PRIMARY KEY (name)
)
We should declare the data source in our Spring Boot application’s properties file so that the DataSource bean can be Autowired.
我们应该在Spring Boot应用程序的属性文件中声明数据源,这样DataSourcebean就可以Autowired。
Here we use the application.yml to define the data source of the H2 database:
这里我们使用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:
Let’s config the LockProvider with the data source configuration above.
让我们用上面的数据源配置来配置LockProvider。
Spring can make it pretty straightforward:
Spring可以让它变得很直接。
@Configuration
public class SchedulerConfiguration {
@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource);
}
}
Other configuration requirements we have to provide are the @EnableScheduling and @EnableSchedulerLock annotations on our Spring configuration class:
我们必须提供的其他配置要求是我们Spring配置类上的@EnableScheduling和@EnableSchedulerLock注解。
@SpringBootApplication
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class Application {
public static void main(String[] args) {
SpringApplication.run(SpringApplication.class, args);
}
}
The defaultLockAtMostFor parameter specifies the default amount of time the lock should be kept in case the executing node dies. It uses the ISO8601 Duration format.
defaultLockAtMostFor参数指定了在执行节点死亡的情况下锁应该被保留的默认时间。它使用ISO8601期限格式。
In the next section, we’ll see how to override this default.
在下一节,我们将看到如何覆盖这个默认值。
4. Creating Tasks
4.创建任务
To create a scheduled task handled by ShedLock, we simply put the @Scheduled and @SchedulerLock annotations on a method:
为了创建一个由ShedLock处理的计划任务,我们只需将@Scheduled和@SchedulerLock注解放在一个方法上。
@Component
class BaeldungTaskScheduler {
@Scheduled(cron = "0 0/15 * * * ?")
@SchedulerLock(name = "TaskScheduler_scheduledTask",
lockAtLeastForString = "PT5M", lockAtMostForString = "PT14M")
public void scheduledTask() {
// ...
}
}
First, let’s look at @Scheduled. It supports the cron format, with this expression meaning “every 15 minutes.”
首先,让我们看看@Scheduled。它支持cron格式,这种表达方式意味着 “每15分钟”。
Next, taking a look at @SchedulerLock, the name parameter has to be unique, and ClassName_methodName is typically enough to achieve that. We don’t want more than one run of this method happening at the same time, and ShedLock uses the unique name to achieve that.
接下来,看看@SchedulerLock,name参数必须是唯一的,而ClassName_methodName通常足以实现这一点。我们不希望这个方法在同一时间有多个运行,ShedLock使用唯一的名称来实现这一点。
We’ve also added a couple of optional parameters.
我们还增加了几个可选参数。
First, we added lockAtLeastForString so that we can put some distance between method invocations. Using “PT5M” means that this method will hold the lock for five minutes, at a minimum. In other words, that means that this method can be run by ShedLock no more often than every five minutes.
首先,我们添加了lockAtLeastForString,这样我们就可以在方法的调用之间拉开一些距离。使用“PT5M”意味着这个方法将至少保持5分钟的锁。换句话说,这意味着这个方法可以被ShedLock运行的频率不超过每五分钟。
Next, we added lockAtMostForString to specify how long the lock should be kept in case the executing node dies. Using “PT14M” means that it will be locked for no longer than 14 minutes.
接下来,我们添加了lockAtMostForString来指定在执行节点死亡的情况下,锁应该被保留多长时间。使用“PT14M” 意味着它将被锁定不超过14分钟。
In normal situations, ShedLock releases the lock directly after the task finishes. Now, we didn’t have to do that because there is a default provided in @EnableSchedulerLock, but we’ve chosen to override that here.
在正常情况下,ShedLock在任务完成后直接释放锁。现在,我们不必这样做,因为在@EnableSchedulerLock中提供了一个默认值,但是我们选择在这里覆盖它。
5. Conclusion
5.总结
In this article, we learned how to create and synchronize scheduled tasks using ShedLock.
在这篇文章中,我们学习了如何使用ShedLock创建和同步计划任务。
As always, all source code is available over on GitHub.
一如既往,所有的源代码都可以在GitHub上找到。