spring-task
sprngtask是spring的任务调度框架,可以实现简单的定时任务调用
上手
-
依赖:springboot项目不需要额外进行依赖
-
使用注解
@EnableScheduling
开启springtask -
配置具体任务
@Component @Slf4j public class MyTask { @Scheduled(fixedDelay = 2000)//每2秒触发一次 public void test1(){ log.info("test1---》{}", LocalDateTime.now()); } @Scheduled(cron = "0/2 * * * * ?")//使用cron表达式,每2秒触发一次 public void test2(){ log.info("test2---》{}", LocalDateTime.now()); } }
注意:此时执行项目,默认使用同一个现场进行执行,前一个任务执行时间会影响到后一个任务的调用时机
需要额外配置:
@Configuration public class ScheduleConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { //设置2个线程执行任务,这样就允许两个任务并行执行 taskRegistrar.setScheduler(Executors.newScheduledThreadPool(2)); } }
动态任务
springtask是可以实现和quartz类似的动态定时任务的
-
cron表达式类
//这里是为了简单,实际中可以在数据库中获取 @Component @Data public class DynamicCronExpression { private String cron = "*/2 * * * * ?"; }
-
任务
@Component @Slf4j public class MyTask { //这里不需要添加@Scheduled注解 public void test(){ log.info("自定义定时任务"); } }
-
配置类
@Configuration @Slf4j public class DynamicScheduleConfig implements SchedulingConfigurer { //表达式类 @Autowired private DynamicCronExpression dynamicCronExpression; //任务 @Autowired private MyTask myTask; @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { //参数1:当前要执行的任务,参数2:设置任务的触发表达式 taskRegistrar.addTriggerTask(()->myTask.test(),triggerContext -> { log.info("设置当前的cron表达式:{}",dynamicCronExpression.getCron()); return new CronTrigger(dynamicCronExpression.getCron()) .nextExecutionTime(triggerContext); }); //设置触发任务 } }
-
调用方
@RestController @RequestMapping("task") @Slf4j public class TaskController { @Autowired private DynamicCronExpression dynamicCronExpression; @PutMapping("set") public void setCorn(String corn){ log.info("修改corn表达式为:{}",corn); dynamicCronExpression.setCron(corn); } }
分布式场景
springtask自身无法胜任分布式场景,需要借助外部组件ShedLock
-
导入依赖
<!-- shedlock依赖 --> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-spring</artifactId> <version>4.29.0</version> </dependency> <!-- shedlock使用redis依赖 --> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-provider-redis-spring</artifactId> <version>4.29.0</version> </dependency> <!-- redis依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
-
在配置文件中配置redis相关信息
-
编写配置类
@Configuration //分布式任务调度如果被强制霸占,那么其它的节点是无法访问的 @EnableSchedulerLock(defaultLockAtMostFor = "PT30S")//30秒强制释放锁 public class ShedLockConfig { @Bean public LockProvider lockProvider(RedisConnectionFactory factory){ //lock是redis中的锁名称,这里直接写死。实际开发中建议使用环境名等 return new RedisLockProvider(factory,"lock"); } }
-
在任务上加锁
@Component @Slf4j public class ShedLockTask { @SneakyThrows @Scheduled(cron = "*/2 * * * * ?") //name:锁名称,相同名称的会互斥 //lockAtLeastFor:成功执行定时任务时任务节点所能拥有独占锁的最短时间 //lockAtMostFor:成功执行定时任务时任务节点所能拥有独占锁的最长时间 @SchedulerLock(name = "task",lockAtLeastFor = "2000")//2秒后开启其它任务 public void task1(){ log.info("task1"); TimeUnit.SECONDS.sleep(1); } }