序
本文主要解析一下shedlock的实现。
LockProvider
shedlock-core-0.16.1-sources.jar!/net/javacrumbs/shedlock/core/LockProvider.java
public interface LockProvider {
/**
* @return If empty optional has been returned, lock could not be acquired. The lock
* has to be released by the callee.
*/
Optional lock(LockConfiguration lockConfiguration);
}
LockProvider入参是lockConfiguration,返回SimpleLock。
StorageBasedLockProvider
shedlock-core-0.16.1-sources.jar!/net/javacrumbs/shedlock/support/StorageBasedLockProvider.java
public class StorageBasedLockProvider implements LockProvider {
private final StorageAccessor storageAccessor;
private final LockRecordRegistry lockRecordRegistry = new LockRecordRegistry();
protected StorageBasedLockProvider(StorageAccessor storageAccessor) {
this.storageAccessor = storageAccessor;
}
@Override
public Optional lock(LockConfiguration lockConfiguration) {
boolean lockObtained = doLock(lockConfiguration);
if (lockObtained) {
return Optional.of(new StorageLock(lockConfiguration, storageAccessor));
} else {
return Optional.empty();
}
}
/**
* Sets lockUntil according to LockConfiguration if current lockUntil <= now
*/
protected boolean doLock(LockConfiguration lockConfiguration) {
String name = lockConfiguration.getName();
if (!lockRecordRegistry.lockRecordRecentlyCreated(name)) {
// create document in case it does not exist yet
if (storageAccessor.insertRecord(lockConfiguration)) {
lockRecordRegistry.addLockRecord(name);
return true;
}
lockRecordRegistry.addLockRecord(name);
}
return storageAccessor.updateRecord(lockConfiguration);
}
private static class StorageLock implements SimpleLock {
private final LockConfiguration lockConfiguration;
private final StorageAccessor storageAccessor;
StorageLock(LockConfiguration lockConfiguration, StorageAccessor storageAccessor) {
this.lockConfiguration = lockConfiguration;
this.storageAccessor = storageAccessor;
}
@Override
public void unlock() {
storageAccessor.unlock(lockConfiguration);
}
}
}
使用StorageAccessor来实现加锁
LockManager
shedlock-core-0.16.1-sources.jar!/net/javacrumbs/shedlock/core/LockManager.java
/**
* Executes task if not locked.
*/
public interface LockManager {
void executeWithLock(Runnable task);
}
默认实现
shedlock-core-0.16.1-sources.jar!/net/javacrumbs/shedlock/core/DefaultLockManager.java
public class DefaultLockManager implements LockManager {
private static final Logger logger = LoggerFactory.getLogger(DefaultLockManager.class);
private final LockingTaskExecutor lockingTaskExecutor;
private final LockConfigurationExtractor lockConfigurationExtractor;
public DefaultLockManager(LockProvider lockProvider, LockConfigurationExtractor lockConfigurationExtractor) {
this(new DefaultLockingTaskExecutor(lockProvider), lockConfigurationExtractor);
}
public DefaultLockManager(LockingTaskExecutor lockingTaskExecutor, LockConfigurationExtractor lockConfigurationExtractor) {
this.lockingTaskExecutor = requireNonNull(lockingTaskExecutor);
this.lockConfigurationExtractor = requireNonNull(lockConfigurationExtractor);
}
@Override
public void executeWithLock(Runnable task) {
Optional lockConfigOptional = lockConfigurationExtractor.getLockConfiguration(task);
if (!lockConfigOptional.isPresent()) {
logger.debug("No lock configuration for {}. Executing without lock.", task);
task.run();
} else {
lockingTaskExecutor.executeWithLock(task, lockConfigOptional.get());
}
}
}
委托给lockingTaskExecutor来加锁
shedlock-core-0.16.1-sources.jar!/net/javacrumbs/shedlock/core/DefaultLockingTaskExecutor.java
public class DefaultLockingTaskExecutor implements LockingTaskExecutor {
private static final Logger logger = LoggerFactory.getLogger(DefaultLockingTaskExecutor.class);
private final LockProvider lockProvider;
public DefaultLockingTaskExecutor(LockProvider lockProvider) {
this.lockProvider = requireNonNull(lockProvider);
}
@Override
public void executeWithLock(Runnable task, LockConfiguration lockConfig) {
Optional lock = lockProvider.lock(lockConfig);
if (lock.isPresent()) {
try {
logger.debug("Locked {}.", lockConfig.getName());
task.run();
} finally {
lock.get().unlock();
logger.debug("Unlocked {}.", lockConfig.getName());
}
} else {
logger.debug("Not executing {}. It's locked.", lockConfig.getName());
}
}
}
这里跟lockProvider衔接上
SpringLockableTaskSchedulerFactoryBean(偷梁换柱
)
shedlock-spring-0.16.1-sources.jar!/net/javacrumbs/shedlock/spring/SpringLockableTaskSchedulerFactoryBean.java
@Override
public Class> getObjectType() {
return LockableTaskScheduler.class;
}
@Override
protected LockableTaskScheduler createInstance() throws Exception {
return new LockableTaskScheduler(
taskScheduler,
new DefaultLockManager(lockProvider, new SpringLockConfigurationExtractor(defaultLockAtMostFor, defaultLockAtLeastFor, embeddedValueResolver))
);
}
主要是LockableTaskScheduler的工厂方法
LockableTaskScheduler(task scheduler lock wrapper
)
shedlock-spring-0.16.1-sources.jar!/net/javacrumbs/shedlock/spring/LockableTaskScheduler.java
public class LockableTaskScheduler implements TaskScheduler, DisposableBean {
private final TaskScheduler taskScheduler;
private final LockManager lockManager;
public LockableTaskScheduler(TaskScheduler taskScheduler, LockManager lockManager) {
this.taskScheduler = requireNonNull(taskScheduler);
this.lockManager = requireNonNull(lockManager);
}
@Override
public ScheduledFuture> schedule(Runnable task, Trigger trigger) {
return taskScheduler.schedule(wrap(task), trigger);
}
@Override
public ScheduledFuture> schedule(Runnable task, Date startTime) {
return taskScheduler.schedule(wrap(task), startTime);
}
@Override
public ScheduledFuture> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
return taskScheduler.scheduleAtFixedRate(wrap(task), startTime, period);
}
@Override
public ScheduledFuture> scheduleAtFixedRate(Runnable task, long period) {
return taskScheduler.scheduleAtFixedRate(wrap(task), period);
}
@Override
public ScheduledFuture> scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
return taskScheduler.scheduleWithFixedDelay(wrap(task), startTime, delay);
}
@Override
public ScheduledFuture> scheduleWithFixedDelay(Runnable task, long delay) {
return taskScheduler.scheduleWithFixedDelay(wrap(task), delay);
}
private Runnable wrap(Runnable task) {
return new LockableRunnable(task, lockManager);
}
@Override
public void destroy() throws Exception {
if (taskScheduler instanceof DisposableBean) {
((DisposableBean) taskScheduler).destroy();
}
}
}
对task scheduler包装了一层,织入了lock的逻辑
问题
上面将了半天,讲了lockProvider以及lockManager,还有LockableTaskScheduler是如何给task scheduler加上锁的,还有LockableTaskScheduler的工厂方法SpringLockableTaskSchedulerFactoryBean。那么问题来了,spring的schedule凭什么就使用你配置的LockableTaskScheduler呢?
@Bean
public ScheduledLockConfiguration scheduledLockConfiguration(LockProvider lockProvider) {
return ScheduledLockConfigurationBuilder
.withLockProvider(lockProvider)
.withPoolSize(10)
.withDefaultLockAtMostFor(Duration.ofMinutes(10))
.build();
}
这种配置仅仅当spring工厂里头没有配置taskScheduler的时候,起作用。如果项目已经显示指定taskScheduler的时候,那么就不会使用LockableTaskScheduler。不过可以通过实现SchedulingConfigurer接口强制指定使用LockableTaskScheduler。
doc
使用shedlock将spring schedule上锁