轉載自:
https://www.cnblogs.com/gutousu/p/10235160.html
spring的定時任務經常被各個服務用到,比如定時清理日誌,定時提醒,
比較方便的就是用Scheduled註解了
簡單的配置一下就能用了
@EnableScheduling
@SpringBootApplication
public class ScheduledLockApplication {
public static void main(String[] args) {
SpringApplication.run(ScheduledLockApplication.class, args);
}
}
這裏每2秒打印一下當前時間
@Component
public class ScheduledLock
{
@Scheduled(cron = "0/2 * * * * ?")
public void run()
{
System.out.print(new Date().toString() + "\n");
}
}
但是!
有一天服務的壓力過大,一個服務支撐不住了,我們要考慮部署多個服務來分散壓力
這時問題就來了
你突然發現你的定時系統,在各個服務上全她丫的跑起來了,做着同樣的事情,這必然不是我們想要的結果
這時你一定會想辦法,讓定時只執行一次
比如一個服務一個配置文件,在配置文件中控制定時的開關
再比如通過數據庫的讀寫來控制定時的開關
詳盡任何辦法,其實這些都是一些不錯的解決辦法
但是!
有一個更方便的東西
那就是shedlock
就叫她分佈式定時任務鎖吧
她的鎖分好多種
Mongo,Redis,Hazelcast,ZooKeeper,還有所有帶JDBC的東西
這玩意用起來也特簡單
她的包
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>2.2.0</version>
</dependency>
這裏用JDBC的鎖
再添加一個包
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>2.2.0</version>
</dependency>
對她進行一下配置,創建一個她要用的bean
@Configuration
public class ScheduledLockConfig
{
@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource);
}
@Bean
public ScheduledLockConfiguration scheduledLockConfiguration(LockProvider lockProvider) {
return ScheduledLockConfigurationBuilder
.withLockProvider(lockProvider)
.withPoolSize(10)
.withDefaultLockAtMostFor(Duration.ofMinutes(10))
.build();
}
}
我用的mysql數據庫
在數據庫中添加一張名爲shedlock表
CREATE TABLE `shedlock` (
`name` varchar(765) DEFAULT NULL,
`lock_until` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`locked_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`locked_by` varchar(765) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
這張表也是她要用的,她通過修改數據庫表中的數據實現鎖
裏面有四個字段
主鍵name:每個定時任務的一個名字
locked_at:鎖的開始時間
lock_until:鎖的結束時間
再定時開始時,會更新這兩個時間,在時間之內的定時是不會被執行的
在啓動類上加上註解EnableSchedulerLock,開啓定時任務鎖,指定一個默認的鎖的時間
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
@SpringBootApplication
public class ScheduledLockApplication {
public static void main(String[] args) {
SpringApplication.run(ScheduledLockApplication.class, args);
}
}
在栗子中添加註解SchedulerLock
@Component
public class ScheduledLock
{
private static final int lockTime = 1000;
@Scheduled(cron = "0/2 * * * * ?")
@SchedulerLock(name = "TaskScheduler_scheduledTask", lockAtMostFor = lockTime, lockAtLeastFor = lockTime)
public void run()
{
System.out.print(new Date().toString() + "\n");
}
}
這個註解有五個參數
name:定時任務的名字,就是數據庫中的內個主鍵
lockAtMostFor:鎖的最大時間單位爲毫秒
lockAtMostForString:最大時間的字符串形式,例如:PT30S 代表30秒
lockAtLeastFor:鎖的最小時間單位爲毫秒
lockAtLeastForString:最小時間的字符串形式
好了,起兩個項目讓她跑起來,看看結果
雖然不是很規律,但是沒有重複的時間