简介
Spring Boot中使用内置的schedule时,在多个实例部署的情况下,如果只想让其中一个实例执行,可以自己用redis、zookeeper等实现,也可以直接用第三方实现。下面介绍其中一种实现:shedlock。
Shedlock
shedlock的集成比较简单,首先在start.spring.io生成Spring Boot的demo包,再引入shedlock相关的依赖:
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-redis-spring</artifactId>
<version>4.41.0</version>
</dependency>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>4.41.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
由于是使用redis来实现锁,所以需要增加spring data redis相关依赖。
然后在启动类加上开启定时任务的注解:
@EnableScheduling
@SpringBootApplication
public class SchedulerLockApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerLockApplication.class, args);
}
}
再加上对应的注解配置类:
@Configuration
@EnableSchedulerLock(defaultLockAtMostFor = "5m")
public class SchedulerLockConfig {
@Bean
public LockProvider lockProvider(RedisConnectionFactory redisConnectionFactory){
return new RedisLockProvider(redisConnectionFactory);
}
}
-
@EnableSchedulerLock 注解就是开启SchedulerLock,必须配置的参数
defaultLockAtMostFor
表示锁最长存在多久。避免比如实例挂掉的情况下,锁无法释放的情况 -
LockProvider有多种实现,如JDBC、redis、zookeeper等,这里选用的是redis
下面是执行任务的schedule相关类:
@Slf4j
@Component
public class ScheduleTask {
@Scheduled(cron = "0 0/1 * * * ?")
@SchedulerLock(name = "taskExecuteLock", lockAtLeastFor = "10s")
public void taskExecute() {
LockAssert.assertLocked();
log.info("task execute ...");
}
}
-
@SchedulerLock 注解的name表示锁的名字,
lockAtLeastFor
是即使任务执行结束,也让锁保留的一段时间的配置。目的是为了防止任务很快执行完,锁也很快释放掉,导致另外有些慢的实例认为还没有执行而导致的重复执行 -
LockAssert.assertLocked()
的作用是为了保证该次执行获取到了锁。比如有些情况下,错误的配置导致注解没有生效,那么执行到了这段就会报错,方便确认锁确实已经生效
总结
可以看到有了shedlock的支持,可以轻松实现多个实例,只执行一次schedule任务。
参考资料
[1]示例工程:spring-boot-demos/scheduler-lock-demo fengdongyi/spring-boot-demos (github.com)
评论
发表评论