SpringBoot整合定时任务和异步任务
一、定时任务
SpringBoot整合quartz-scheduler,执行定时任务。
1、开启定时任务
@EnableScheduling2、开启一个定时任务
@Scheduled3、编写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)