🧑🎓 个人主页:Silence Lamb
📖 本章内容:【SpringBoot-执行定时任务】
⛲静态定时任务—基于注解
- SpringBoot 中的
@Scheduled
注解为定时任务提供了一种很简单的实现 - 只需要在注解中加上一些属性,例如 fixedRate、fixedDelay、cron
- 并且在启动类上面加上 @EnableScheduling 注解,就可以启动一个定时任务了
- 基于注解@Scheduled默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响
1️⃣开启定时任务
🌳 在启动类上面加上 @EnableScheduling 注解
@EnableScheduling
@SpringBootApplication
public class SpringbootTimeApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootTimeApplication.class, args);
}
}
2️⃣创建定时任务
/**
* 定时任务的使用
**/
@Component //注入到容器
public class Task {
@Scheduled(cron = "0/5 * * * * ? ") //每5秒执行一次
public void execute() {
int count = 0;
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //设置日期格式
System.out.println("执行第" + count++ + "次定时任务_" + df.format(new Date()));
}
}
🥭动态定时任务—基于配置
1️⃣开启定时任务
🌳 在启动类上面加上 @EnableScheduling 注解
@EnableScheduling
@SpringBootApplication
public class SpringbootTimeApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootTimeApplication.class, args);
}
}
2️⃣创建配置文件
🌳 将 cron 表达式配在 application.yml 中
#application.yml中的配置
scheduled:
cron: 0/5 * * * * ?
@Component
public class TestTask {
private static SimpleDateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Scheduled(cron = "${scheduled.cron}")
public void test(){
System.out.println(dateFmt.format(new Date()) + " : 执行定时任务");
}
}
🌳 如何关闭定时任务
#application.yml中的配置
scheduled:
cron: "-"
🌳 为定时任务设置开关
#application.yml中的配置
scheduled:
cron: 0/5 * * * * ?
enable:
scheduled: true # @Schedule 定时任务的开true/关false
- 启动类上面的 @EnableScheduling 需要去掉
- 不去除定时将一直生效,一直为true
- 创建ScheduledCondtion类读取配置
🌳 解决不去除定时将一直生效,一直为true
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class ScheduledCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//读取配置中的属性
return Boolean.parseBoolean(context.getEnvironment().getProperty("enable.scheduled"));
}
}
- 创建一个 ScheduledConfig 配置类
- 就是以 ScheduledCondtion 为条件,决定是否创建 bean
@Configuration
public class ScheduledConfig {
// 根据配置文件中的内容,决定是否创建 bean
@Conditional(ScheduledCondition.class)
@Bean
public ScheduledAnnotationBeanPostProcessor processor() {
return new ScheduledAnnotationBeanPostProcessor();
}
}
🥌多线程定时任务-使用@Async注解
1️⃣改成异步执行
// 需要构建一个合理的线程池也是一个关键,否则提交的任务也会在自己构建的线程池中阻塞
ExecutorService service = Executors.newFixedThreadPool(3);
@Scheduled(cron = "0/1 * * * * ? ")
public void task() {
service.execute(() -> {
log.info("执行-task()," + "异步threadId:" + Thread.currentThread().getId());
//模拟长时间执行,比如IO操作,http请求
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
@Scheduled(cron = "0/1 * * * * ? ")
public void job() {
service.execute(() -> {
log.info("执行-job()," + "异步threadId:" + Thread.currentThread().getId());
});
}
2️⃣配置成多线程执行
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@Configuration
@EnableScheduling
public class MySchedulingConfigurer implements SchedulingConfigurer {
/**
* 重写配置定时任务的方法.
*/
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.setScheduler(taskScheduler());
}
@Bean(name = "taskExecutor")
public ScheduledExecutorService taskScheduler() {
//创建线程池
return new ScheduledThreadPoolExecutor(5,
new BasicThreadFactory.Builder().namingPattern("scheduler-pool-%d").daemon(true).build());
}
}
3️⃣使用@Async注解
/**
* 基于注解设定多线程定时任务.
*/
@Component
@EnableScheduling // 1.开启定时任务
@EnableAsync // 2.开启多线程
public class MultithreadScheduleTask{
@Async
@Scheduled(fixedDelay = 1000) //间隔1秒
public void first() throws InterruptedException {
System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() +
",线程 : " + Thread.currentThread().getName() + ",异步threadId:" + Thread.currentThread().getId());
Thread.sleep(1000 * 10);
}
@Async
@Scheduled(fixedDelay = 2000)
public void second() {
System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() +
",线程 : " + Thread.currentThread().getName() + ",异步threadId:" + Thread.currentThread().getId());
}
}