本文主要解析一下shedlock的實現。java
shedlock-core-0.16.1-sources.jar!/net/javacrumbs/shedlock/core/LockProvider.javaspring
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<SimpleLock> lock(LockConfiguration lockConfiguration); }
LockProvider入參是lockConfiguration,返回SimpleLock。segmentfault
shedlock-core-0.16.1-sources.jar!/net/javacrumbs/shedlock/support/StorageBasedLockProvider.javaapp
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<SimpleLock> 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來實現加鎖ide
shedlock-core-0.16.1-sources.jar!/net/javacrumbs/shedlock/core/LockManager.javaui
/** * Executes task if not locked. */ public interface LockManager { void executeWithLock(Runnable task); }
默認實現
shedlock-core-0.16.1-sources.jar!/net/javacrumbs/shedlock/core/DefaultLockManager.javathis
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<LockConfiguration> 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.javadebug
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<SimpleLock> 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銜接上code
偷樑換柱
)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的工廠方法
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。