springboot定时任务与线程池配置


0、前言

在 Spring Boot 中,定时任务的执行可以通过 @Scheduled 注解来实现。为了更好地管理和优化多任务并发执行,配置合适的线程池是非常重要的。本文将介绍如何在 Spring Boot 中配置定时任务,并通过配置文件或编程方式设置线程池。

一、启用定时任务支持

在 Spring Boot 应用的主类中,使用 @EnableScheduling 注解来启用定时任务支持。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

注:@EnableScheduling不一定只能放在Application.java中,也可以放在其他Bean上。比如后面的SchedulerConfig.java,自选放一个位置即可。

@Configuration
@EnableScheduling
public class SchedulerConfig {

}

二、定义定时任务

在 Spring Boot 中,可以通过 @Scheduled 注解来定义定时任务。以下示例展示了一个每隔 5 秒执行一次的任务:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduledTasks {

    @Scheduled(fixedRate = 5000)
    public void reportCurrentTime() {
        System.out.println("Current Time: " + System.currentTimeMillis());
    }
}

注:@Scheduled可以是cron表达式,以下为一些使用方式:

  • fixedRate (固定速率)

@Scheduled(fixedRate = X) 表示任务以固定速率执行,任务之间的间隔时间是固定的,不考虑任务的执行时间。

@Scheduled(fixedRate = 5000)
public void taskWithFixedRate() {
    System.out.println("Task with fixed rate - " + System.currentTimeMillis());
}

上面的示例表示任务每 5 秒执行一次,无论前一个任务是否完成。

  • fixedDelay (固定延迟)

@Scheduled(fixedDelay = X) 表示任务在前一个任务完成之后,再等待固定的时间间隔执行下一次任务。

@Scheduled(fixedDelay = 5000)
public void taskWithFixedDelay() {
    System.out.println("Task with fixed delay - " + System.currentTimeMillis());
}

此示例表示任务每 5 秒执行一次,但每次执行会等待前一个任务完成后,再延迟 5 秒。

  • initialDelay (初始延迟)

@Scheduled(initialDelay = X, fixedRate = Y)@Scheduled(initialDelay = X, fixedDelay = Y) 允许你在任务开始前指定一个初始延迟时间。

@Scheduled(initialDelay = 10000, fixedRate = 5000)
public void taskWithInitialDelay() {
    System.out.println("Task with initial delay - " + System.currentTimeMillis());
}

此示例表示任务将在启动后等待 10 秒,然后每 5 秒执行一次。

  • 使用 Cron 表达式

@Scheduled(cron = "cron_expression") 可以使用 Cron 表达式来精确地定义任务的执行时间。

@Scheduled(cron = "0 0/5 * * * ?")
public void taskWithCronExpression() {
    System.out.println("Task with cron expression - " + System.currentTimeMillis());
}

上面的示例表示任务每 5 分钟执行一次。

三、配置线程池

默认的定时任务是单线程的,可用于测试,但如果用于生产环境,建议进行线程池配置以适应于正常环境中使用。

1.方式一:通过配置文件

Spring Boot 提供了一些默认的属性来配置定时任务的线程池。通过 application.properties 或 application.yml 文件可以方便地进行配置。

  • 使用 application.properties
# 设置线程池的大小
spring.task.scheduling.pool.size=10

# 设置线程名称的前缀
spring.task.scheduling.thread-name-prefix=Scheduler-

# 设置等待终止的秒数
spring.task.scheduling.shutdown.await-termination=true
spring.task.scheduling.shutdown.await-termination-period=60s

  • 使用 application.yml
spring:
  task:
    scheduling:
      pool:
        size: 10 # 设置线程池的大小
      thread-name-prefix: Scheduler- # 设置线程名称的前缀
      shutdown:
        await-termination: true # 是否等待所有任务完成再终止
        await-termination-period: 60s # 等待终止的秒数

2.方式二:配置线程池(使用编程方式)

如果需要更灵活的配置,可以在配置类中定义 ThreadPoolTaskScheduler:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

@Configuration
public class SchedulerConfig {

    @Bean
    public ThreadPoolTaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(10); // 设置线程池大小
        scheduler.setThreadNamePrefix("Scheduler-");// 线程名称前缀
        scheduler.setAwaitTerminationSeconds(60); //在应用关闭时,如果不希望立即中断正在执行的任务,可以设置等待终止的时间,让任务有机会完成
        scheduler.setWaitForTasksToCompleteOnShutdown(true); //是否等待所有任务完成再终止
        return scheduler;
    }
}

四、任务的异常处理

默认情况下,如果定时任务抛出未捕获的异常,任务将不会继续执行。因为建议在编写定时任务时进行处理异常:

  • 未进行异常处理场景
	@Scheduled(cron = "0/5 * * * * ?")
	public void deleteSysLog() {
		int result = 1 / 0; // 故意模拟一个异常来演示
		log.info("{}", result);
	}

比如上面的定时任务,会在执行过程中出现异常,java.lang.ArithmeticException: / by zero,但定时任务的方法没有进行异常处理,定时任务在异常发生后,后续不再会进行任务调度,因此建议为保持任务的持续调度,需要在定义定时任务的方法中进行异常处理。。

  • 改造后
	@Scheduled(cron = "0/5 * * * * ?")
	public void deleteSysLog() {
		try {
			int result = 1 / 0;
			log.info("{}", result);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
	}

改造后的定时任务,即使任务出现异常后,下一轮仍然会继续调度。

五、案例进行sys_log表的日志定时清理

比如我的web应用程序有一张sys_log表,每天会产生操作日志数据,有begin_time字段,我可以通过定义每小时的定时任务进行日志清理,保留3个月内的日志数据

1.定义定时任务类

package cn.gzsendi.modules.system.scheduler;

import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import cn.gzsendi.modules.framework.utils.RedissonLockUtils;
import cn.gzsendi.modules.system.mapper.SysLogMapper;
import lombok.extern.slf4j.Slf4j;

/**
 * 定义日志清理定时任务任务配置类
 * syslog.clear.enabled: 是否开启日志清理定时任务
 * matchIfMissing:如果没有找到配置就默认禁用
 */
@Configuration
@ConditionalOnProperty(name = "syslogclear.enabled", havingValue = "true", matchIfMissing = false)
@EnableScheduling
@Slf4j
public class SyslogScheduer {

	/**
	 * 引入日志操作mapper,用于sys_log表的数据清理
	 */
	@Resource
	private SysLogMapper sysLogMapper;

	/**
	 * 每小时执行一次定时任务,清理3个月前的sys_log表数据
	 */
	@Scheduled(cron = "0 0 * * * ?")
	public void deleteSysLog() {

		// 执行日志清除
		try {
			int effectRows = sysLogMapper.deleteBeforeThreeMonths();
			log.info("清理sys_log任务执行完成,删除日志数据 {} 条.", effectRows);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}

	}

}

说明:@ConditionalOnProperty(name = “syslogclear.enabled”, havingValue = “true”, matchIfMissing = true)

  • name = “syslogclear.enabled”: 这是要检查的属性名。如果该属性在配置文件(例如 application.properties 或 application.yml)中存在,则其值将用于条件判断。

  • havingValue = “true”: 这是 name 属性对应的值,当配置文件中的属性值与此处的值匹配时,条件为 true,则组件会被加载。

  • matchIfMissing = true: 如果配置文件中没有定义 syslogclear.enabled 这个属性,则默认认为条件为 true,因此组件会被加载。也就是说,如果属性缺失,将使用默认值(这里是 true)来判断是否启用组件。

SysLogMapper.java,采用Mybatis定义一个清理日志接口方法

	/**
	 * 删除3个月前的日志
	 * @return
	 */
	public int deleteBeforeThreeMonths();

SysLogMapper.xml,对应的sql语句

	<delete id="deleteBeforeThreeMonths" >
		DELETE FROM sys_log WHERE begin_time &lt; NOW() - INTERVAL '3 months'
	</delete>

2.修改配置文件application.yml

修改配置文件并支持定时任务线程池处理

# application.yml中增加

spring:
  task:
    scheduling:
      pool:
        size: 10 # 设置线程池的大小
      thread-name-prefix: Scheduler- # 设置线程名称的前缀  
  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Java Spring Boot配置定时任务线程池,您可以按照以下步骤操作: 1. 首先,您需要在Spring Boot应用程序中添加依赖项。在您的pom.xml文件中,添加以下依赖项: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> ``` 2. 接下来,您需要创建一个定时任务类。您可以使用`@Scheduled`注解来标记方法,以指定它是一个定时任务。例如,创建一个名为`MyTask`的类,并在其中添加一个定时任务方法: ```java import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class MyTask { @Scheduled(fixedRate = 5000) // 每5秒执行一次 public void runTask() { // 执行您的定时任务逻辑 System.out.println("定时任务执行中..."); } } ``` 3. 然后,您需要在应用程序的主类上添加`@EnableScheduling`注解,以启用定时任务功能。例如: ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } } ``` 4. 最后,您可以根据需要配置线程池Spring Boot使用一个默认的`TaskScheduler`实现,它使用单个线程执行所有的定时任务。如果您希望使用自定义的线程池,您可以创建一个实现了`TaskScheduler`接口的Bean,并进行相应的配置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值