网络小说网站建设,做电子商务网站 费用,快手小程序,wordpress伪静态 加速本文大纲#x1f4d6; 1、背景#x1f342;2、SchedulerLock注解3、实现原理 1、背景#x1f342;
Spring生态下#xff0c;日常开发定时任务#xff0c;使用Spring Task框架还是很常见的选择#xff0c;但Spring Task并不是为分布式环境设计的#xff0c;分布式环境下… 本文大纲 1、背景2、SchedulerLock注解3、实现原理 1、背景
Spring生态下日常开发定时任务使用Spring Task框架还是很常见的选择但Spring Task并不是为分布式环境设计的分布式环境下服务被部署到多个节点一个节点上运行着一个独立的Jvm各个节点之间并不会协调通讯因此同一个定时任务会在每一个节点上都执行一次导致任务重复执行此时可以考虑使用redis、zookeeper等中间件来实现分布式锁保证一次只有一个节点执行任务当然也可以考虑支持分布式调度等框架如Quartz、xxl-job
2、SchedulerLock注解
在分布式场景下可以使用SchedulerLock注解来弥补Spring Task的缺点注意⚠️这个不是Spring的注解是shedlock库的
package net.javacrumbs.shedlock.spring.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
Retention(RetentionPolicy.RUNTIME)
public interface SchedulerLock {String name() default ;String lockAtMostFor() default ;String lockAtLeastFor() default ;
}SchedulerLock分布式锁的实现方式很多官方也提供了不同中间件的实现示例https://github.com/lukas-krecan/ShedLock/blob/master/README.md这里演示用mysql实现的过程
引入相关依赖注意依赖版本的兼容性
dependencygroupIdnet.javacrumbs.shedlock/groupIdartifactIdshedlock-spring/artifactIdversion4.42.0/version
/dependency
dependencygroupIdnet.javacrumbs.shedlock/groupIdartifactIdshedlock-provider-jdbc-template/artifactIdversion4.42.0/version
/dependency配置锁提供者这里是mysql
import net.javacrumbs.shedlock.core.LockProvider;
import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;
import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;import javax.sql.DataSource;Configuration
EnableScheduling //这个是Spring注解开启Spring task功能的
EnableSchedulerLock(defaultLockAtMostFor 30m, defaultLockAtLeastFor 1m)
public class LockConfig {Beanpublic LockProvider lockProvider(Qualifier(primaryDataSource) DataSource dataSource) {return new JdbcTemplateLockProvider(JdbcTemplateLockProvider.Configuration.builder()// 使用primaryDataSource这个自定义的数据源和业务接口用一个数据源就行 .withJdbcTemplate(new JdbcTemplate(dataSource)).usingDbTime().build());}
}对应的库里建表
CREATE TABLE shedlock(name VARCHAR(64) NOT NULL, lock_until TIMESTAMP(3) NOT NULL,locked_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), locked_by VARCHAR(255) NOT NULL, PRIMARY KEY (name));使用
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;...Scheduled(cron 0 0 * * * *)
SchedulerLock(name your.task.schedule.lockName) //锁名称自定义可以驼峰可以点点点
public void scheduledTask() {// do something
}补充下上面配置类里写了默认的锁持有的最长时间和最短时间对于特定任务可以自定义锁持有时间
SchedulerLock(name TaskScheduler_CommonWhiteRisksReport, lockAtMostFor ${task.schedulerLock.lockAtMost}, lockAtLeastFor ${task.schedulerLock.lockAtLeast})task:schedulerLock:lockAtMost: PT8MlockAtLeast: PT8M# Duration的格式是ISO-8601例如
# PT8M 表示8分钟
# PT30S 表示30秒
# PT1H 表示1小时3、实现原理
加EnableSchedulerLock注解后会引入SchedulerLockConfigurationSelector类 SchedulerLockConfigurationSelector类通过实现ImportSelector类导入了两个BeanLockConfigurationExtractorConfiguration 和 MethodProxyLockConfiguration Sting数组里是要注册成Bean的类的全类名这两步就是ImportSelector接口搭配Import注解声明Bean的方式一种使用 再往下LockConfigurationExtractorConfiguration配置类声明了ExtendedLockConfigurationExtractor这个Bean里面包含了锁的一些配置信息如默认最大持有时间这些配置是从注解的属性里拿到的这回配置提取的Bean会带着这些配置信息给下面要提到的另一个Bean使用 另一个配置类MethodProxyLockConfiguration则是声明了MethodProxyScheduledLockAdvisor这个Bean里面通过上面的lockConfigurationExtractor获取锁的一些配置 跟进MethodProxyLockConfiguration类发现其获取了一个切面切面就是包含SchedulerLock注解的方法切面拦截住以后增强的部分是LockingInterceptor对象 而方法增强部分就是根据我们提供的LockProvider来做加锁和释放锁的操作比如mysql向库里写数据Redis的setnx