SpringBoot整合定时任务和异步任务
一、定时任务
SpringBoot整合quartz-scheduler,执行定时任务。
1、开启定时任务
@EnableScheduling
2、开启一个定时任务
@Scheduled
3、编写cron表达式
cron表达式格式请参考官方文档
4、实例
package com.yanxizhu.ifamily.booking.controller.scheduler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* SpringBoot整合Scheduling定时任务
* @author: <a href="mailto:vip@foxmail.com">清风</a>
* @date: 2022/3/15 20:26
* @version: 1.0
*/
@Slf4j
@Component
@EnableScheduling
public class MyScheduler {
/**
* cron表达式
*/
@Scheduled(cron = "1/3 1/1 * * * ? ")
public void sayHell(){
log.info("Hello");
}
}
5、定时任务总结
1、@EnableScheduling 开启一个定时任务
2、@Scheduled 开启一个定时任务
3、编写定时规则,也就是cron表达式。
6、注意事项
- spring中6位组成,不允许第7位的年。
- 在周几的位置,1-7代表周一到周日,MON-SUN
- 定时任务不应该阻塞,默认时阻塞的,应该以异步任务执行。
7、解决方案
解决定时任务阻塞问题:使用异步+定时任务
二、异步任务执行几种方式
1、异步方式提交线程池
可以让业务运行以异步的方式,自己提交到线程池(CompletableFuture异步编排)。
@Slf4j
@Component
@EnableScheduling
public class MyScheduler {
public static ExecutorService executorService = Executors.newFixedThreadPool(10);
/**
* cron表达式
*/
@Scheduled(cron = "1/3 1/1 * * * ? ")
public void sayHell(){
CompletableFuture.runAsync(()->{
//调用server业务方法
}, executorService);
}
}
2、定时任务线程池
支持定时任务线程池(定时任务线程池)。Scheduling自动配置类,默认只有1个线程。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.boot.autoconfigure.task;
import java.util.concurrent.ScheduledExecutorService;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.LazyInitializationExcludeFilter;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.task.TaskSchedulingProperties.Shutdown;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.task.TaskSchedulerBuilder;
import org.springframework.boot.task.TaskSchedulerCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
@ConditionalOnClass({ThreadPoolTaskScheduler.class})
@Configuration(
proxyBeanMethods = false
)
@EnableConfigurationProperties({TaskSchedulingProperties.class})
@AutoConfigureAfter({TaskExecutionAutoConfiguration.class})
public class TaskSchedulingAutoConfiguration {
public TaskSchedulingAutoConfiguration() {
}
@Bean
@ConditionalOnBean(
name = {"org.springframework.context.annotation.internalScheduledAnnotationProcessor"}
)
@ConditionalOnMissingBean({SchedulingConfigurer.class, TaskScheduler.class, ScheduledExecutorService.class})
public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) {
return builder.build();
}
@Bean
public static LazyInitializationExcludeFilter scheduledBeanLazyInitializationExcludeFilter() {
return new ScheduledBeanLazyInitializationExcludeFilter();
}
@Bean
@ConditionalOnMissingBean
public TaskSchedulerBuilder taskSchedulerBuilder(TaskSchedulingProperties properties, ObjectProvider<TaskSchedulerCustomizer> taskSchedulerCustomizers) {
TaskSchedulerBuilder builder = new TaskSchedulerBuilder();
builder = builder.poolSize(properties.getPool().getSize());
Shutdown shutdown = properties.getShutdown();
builder = builder.awaitTermination(shutdown.isAwaitTermination());
builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
builder = builder.customizers(taskSchedulerCustomizers);
return builder;
}
}
默认只有一个线程
package org.springframework.boot.autoconfigure.task;
import java.time.Duration;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("spring.task.scheduling")
public class TaskSchedulingProperties {
private final TaskSchedulingProperties.Pool pool = new TaskSchedulingProperties.Pool();
private final TaskSchedulingProperties.Shutdown shutdown = new TaskSchedulingProperties.Shutdown();
private String threadNamePrefix = "scheduling-";
public TaskSchedulingProperties() {
}
public TaskSchedulingProperties.Pool getPool() {
return this.pool;
}
public TaskSchedulingProperties.Shutdown getShutdown() {
return this.shutdown;
}
public String getThreadNamePrefix() {
return this.threadNamePrefix;
}
public void setThreadNamePrefix(String threadNamePrefix) {
this.threadNamePrefix = threadNamePrefix;
}
public static class Shutdown {
private boolean awaitTermination;
private Duration awaitTerminationPeriod;
public Shutdown() {
}
public boolean isAwaitTermination() {
return this.awaitTermination;
}
public void setAwaitTermination(boolean awaitTermination) {
this.awaitTermination = awaitTermination;
}
public Duration getAwaitTerminationPeriod() {
return this.awaitTerminationPeriod;
}
public void setAwaitTerminationPeriod(Duration awaitTerminationPeriod) {
this.awaitTerminationPeriod = awaitTerminationPeriod;
}
}
public static class Pool {
private int size = 1;
public Pool() {
}
public int getSize() {
return this.size;
}
public void setSize(int size) {
this.size = size;
}
}
}
配置线程池数量
spring.task.scheduling.pool.size=5
这样定时任务就有5个线程可以执行了,如果1个线程,定时任务就会阻塞。
3、让定时任务执行
@EnableAsync 开启异步任务功能
@Async 在希望异步执行的方法开启异步执行注解,普通方法也可以使用。
默认线程数8
异步任务自动配置类源码:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.boot.autoconfigure.task;
import java.util.concurrent.Executor;
import java.util.stream.Stream;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.task.TaskExecutionProperties.Pool;
import org.springframework.boot.autoconfigure.task.TaskExecutionProperties.Shutdown;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.task.TaskExecutorBuilder;
import org.springframework.boot.task.TaskExecutorCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@ConditionalOnClass({ThreadPoolTaskExecutor.class})
@Configuration(
proxyBeanMethods = false
)
@EnableConfigurationProperties({TaskExecutionProperties.class})
public class TaskExecutionAutoConfiguration {
public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";
public TaskExecutionAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean
public TaskExecutorBuilder taskExecutorBuilder(TaskExecutionProperties properties, ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers, ObjectProvider<TaskDecorator> taskDecorator) {
Pool pool = properties.getPool();
TaskExecutorBuilder builder = new TaskExecutorBuilder();
builder = builder.queueCapacity(pool.getQueueCapacity());
builder = builder.corePoolSize(pool.getCoreSize());
builder = builder.maxPoolSize(pool.getMaxSize());
builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());
builder = builder.keepAlive(pool.getKeepAlive());
Shutdown shutdown = properties.getShutdown();
builder = builder.awaitTermination(shutdown.isAwaitTermination());
builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
Stream var10001 = taskExecutorCustomizers.orderedStream();
var10001.getClass();
builder = builder.customizers(var10001::iterator);
builder = builder.taskDecorator((TaskDecorator)taskDecorator.getIfUnique());
return builder;
}
@Lazy
@Bean(
name = {"applicationTaskExecutor", "taskExecutor"}
)
@ConditionalOnMissingBean({Executor.class})
public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
return builder.build();
}
}
默认线程8
package org.springframework.boot.autoconfigure.task;
import java.time.Duration;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("spring.task.execution")
public class TaskExecutionProperties {
private final TaskExecutionProperties.Pool pool = new TaskExecutionProperties.Pool();
private final TaskExecutionProperties.Shutdown shutdown = new TaskExecutionProperties.Shutdown();
private String threadNamePrefix = "task-";
public TaskExecutionProperties() {
}
public TaskExecutionProperties.Pool getPool() {
return this.pool;
}
public TaskExecutionProperties.Shutdown getShutdown() {
return this.shutdown;
}
public String getThreadNamePrefix() {
return this.threadNamePrefix;
}
public void setThreadNamePrefix(String threadNamePrefix) {
this.threadNamePrefix = threadNamePrefix;
}
public static class Shutdown {
private boolean awaitTermination;
private Duration awaitTerminationPeriod;
public Shutdown() {
}
public boolean isAwaitTermination() {
return this.awaitTermination;
}
public void setAwaitTermination(boolean awaitTermination) {
this.awaitTermination = awaitTermination;
}
public Duration getAwaitTerminationPeriod() {
return this.awaitTerminationPeriod;
}
public void setAwaitTerminationPeriod(Duration awaitTerminationPeriod) {
this.awaitTerminationPeriod = awaitTerminationPeriod;
}
}
public static class Pool {
private int queueCapacity = 2147483647;
private int coreSize = 8;
private int maxSize = 2147483647;
private boolean allowCoreThreadTimeout = true;
private Duration keepAlive = Duration.ofSeconds(60L);
public Pool() {
}
public int getQueueCapacity() {
return this.queueCapacity;
}
public void setQueueCapacity(int queueCapacity) {
this.queueCapacity = queueCapacity;
}
public int getCoreSize() {
return this.coreSize;
}
public void setCoreSize(int coreSize) {
this.coreSize = coreSize;
}
public int getMaxSize() {
return this.maxSize;
}
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
public boolean isAllowCoreThreadTimeout() {
return this.allowCoreThreadTimeout;
}
public void setAllowCoreThreadTimeout(boolean allowCoreThreadTimeout) {
this.allowCoreThreadTimeout = allowCoreThreadTimeout;
}
public Duration getKeepAlive() {
return this.keepAlive;
}
public void setKeepAlive(Duration keepAlive) {
this.keepAlive = keepAlive;
}
}
}
通过配置线程池线程数
spring.task.execution.pool.core-size=5
spring.task.execution.pool.max-size=50
实列
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Slf4j
@Component
@EnableAsync
@EnableScheduling
public class MyScheduler {
public static ExecutorService executorService = Executors.newFixedThreadPool(10);
/**
* cron表达式
*/
@Async
@Scheduled(cron = "1/3 1/1 * * * ? ")
public void sayHell(){
System.out.println("Hello ....");
}
}
要用线程池的时候,自己注入即可用了。
评论 (0)