定时任务一般会存在中大型企业级项目中,为了减少服务器、数据库的压力往往会采用时间段性的去完成某些业务逻辑。SpringBoot为我们内置了定时任务,我们只需要一个注解就可以开启定时为我们所用了。
通过@EnableScheduling
和@Scheduled
开启定时功能
@Scheduled
- 作用:spring定时器(定时执行一次或定时轮询执行一段代码)
- 使用场景:注解在方法上
@EnableScheduling
- 启用spring定时器功能。
定时器的参数写法
定时器的参数有两种写法是用cron表达式,或者使用fixedDelay、fixedRate等参数直接配置
第一种配置方式
项目启动后方法不会执行,而是等到执行周期到了才会执行方法
@Scheduled(cron = "0/5 * * * * ?") public void execute() { log.info("ScheduleTask "+ Thread.currentThread().getName()); } 复制代码
第二种参数方式
项目启动成功后马上执行一次
@Scheduled(fixedRateString="1000") public void execute() { log.info("ScheduleTask "+ Thread.currentThread().getName()); } 复制代码
Scheduled对于线程池的选择顺序
在项目中我们通常不会自己手动创建线程,而是通过统一的线程池来执行方法,使用这种方法来避免多人团队中由于自定义线程导致的资源耗尽的问题。在自定义线程池之前首先要了解Spring在执行异步任务或者方法的时候是怎么选择线程池的。
Scheduled对于线程池的选择顺序如下图所示:
当Spring执行定时任务的时候,首先会在上下文中找类型为TaskScheduler或者名称为taskScheduler的bean,找不到的时候会手动创建一个线程执行此task。
如图分别定义了2个相同类型的线程池,只是bean 的名字不用
Himport cn.hutool.cron.task.Task; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.TaskScheduler; importorg.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; /** @author jiangpeng 卡 @date 2021/1/1514:46 @Configuration public class TaskschedulerPool { @Bean public TaskScheduler threadPoolTaskScheduler(){ finalThreadPoolTaskScheduler taskScheduler =new ThreadPoolTaskScheduler() taskScheduler.setPoolSize(10); taskScheduler.setThreadNamePrefix("Async-threadPoolTaskScheduler-");//必须得先初始化,才能使用 taskScheduler.initialize(); return taskscheduler;} @Bean 当存在同类型的bean时,schedule会选择这个名字的 public TaskScheduler taskScheduler(){ final ThreadPoolTaskScheduler beaskscheduler = new ThreadpoolTaskscheduler(); taskScheduler.setPoolSize(10); taskScheduler.setThreadNamePrefix("my-threadPoolTaskScheduler-"); return taskScheduler;
单元测试代码如下:
package com.mty.jls.scheduleTest; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author jiangpeng * @date 2021/1/1514:55 */ @SpringBootTest( classes = {TaskSchedulerPool.class, AsyncApplicationTests.TestConfig.class} ) @Slf4j @RunWith(SpringJUnit4ClassRunner.class) public class AsyncApplicationTests { @Test public void testCron() { try { Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); } } @Configuration @EnableScheduling public static class TestConfig { @Bean public ScheduleTask getScheduleTask() { return new ScheduleTask(); } @Bean public ScheduleTask2 getScheduleTask2() { return new ScheduleTask2(); } } @Component static class ScheduleTask { @Scheduled(fixedRateString="1000") public void execute() { log.info("ScheduleTask "+ Thread.currentThread().getName()); } } @Component static class ScheduleTask2 { @Scheduled(fixedRateString="2000") public void execute() { log.info("ScheduleTask 2 "+ Thread.currentThread().getName()); } } } 复制代码
执行结果如图:
assed :1 ot 1 test -3s383M75 968[ my - threadPoolTaskScheduler -3]IIF0 c . m . j . s . AsyncApplicationTests - ScheduleIask my - threadPoolTaskScheduler -3 968[ my - threadPoolTaskScheduler -1]IlF0 c . m . j . s . AsyncApplicationTests - ScheduleIask mythreadPoolIaskScheduler -1 968[ my - threadPoolTaskScheduler -1]IIF0 c . m . j . s . AsyncApplicationTests - ScheduleIask 2 my - threadPoolTaskScheduler -1 968[ my - threadPoolTaskScheduler -4]IF0 c . m . j . s . AsyncApplicationTests - ScheduleTask myrthreadPoelTaskScheduler -4