SpringBoot整合定时任务和异步任务

admin
2022-03-15 / 0 评论 / 93 阅读 / 正在检测是否收录...

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:batis@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、注意事项

  1. spring中6位组成,不允许第7位的年。
  2. 在周几的位置,1-7代表周一到周日,MON-SUN
  3. 定时任务不应该阻塞,默认时阻塞的,应该以异步任务执行。

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 ....");
    }
}

要用线程池的时候,自己注入即可用了。

12

评论 (0)

取消