一. 在Spring boot 项目中实现简单的定时任务:
在Spring boot项目中实现定时任务通常用Spring的@Scheduled注解来完成。
示例:
1.首先,在Spring boot 项目中创建一个定时任务类,例如:TaskScheduler:
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class TaskScheduler {
// 每隔5秒执行一次任务
@Scheduled(fixedRate = 5000)
public void scheduledTask() {
System.out.println("定时任务执行啦!");
}
}
2.在启动类或者配置类上添加@EnableScheduling注解,以开启定时任务的支持:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
3.完成以上步骤后,当运行Spring Boot时,定时任务会按照@Scheduled注解中配置的时间间隔执行。
二. @Scheduled注解:
@Scheduled注解是Spring框架中用于配置定时任务的注解之一。通过在方法上添加@Scheduled注解,可以指定方法在特定时间执行,或者以固定时间间隔执行。在使用@Scheduled时,可以指定多种参数,包括fixedDelay(固定延迟时间执行),fixedRate(固定频率执行),cron表达式(按照cron表达式规则执行)等,以满足不同的定时任务需求。
@Scheduled各个参数用法:
fixedDelay:
- 用法:
@Scheduled(fixedDelay = 1000)
- 解释:指定方法执行结束后延迟多久再次执行,单位为毫秒。
- 示例:
@Scheduled(fixedDelay = 5000)
表示每次任务执行结束后延迟 5 秒再次执行。fixedRate:
- 用法:
@Scheduled(fixedRate = 2000)
- 解释:指定方法开始执行后多久再次执行,单位为毫秒。不关心方法执行时间长短,固定频率执行。
- 示例:
@Scheduled(fixedRate = 3000)
表示每隔 3 秒执行一次任务,不论任务执行时间长短。initialDelay:
- 用法:
@Scheduled(initialDelay = 5000, fixedRate = 2000)
- 解释:指定首次执行任务的延迟时间,单位为毫秒。
- 示例:
@Scheduled(initialDelay = 10000, fixedRate = 3000)
表示首次执行任务将在 10 秒后,之后每隔 3 秒执行一次。cron:
- 用法:
@Scheduled(cron = "0 0 12 * * ?")
- 解释:使用 cron 表达式来指定任务执行的时间规则。
- 示例:
@Scheduled(cron = "0 0/5 8-20 * * ?")
表示在每天的上午 8 点到晚上 8 点,每隔 5 分钟执行一次任务。
cron表达式的各个字段及其含义:
- 秒(Seconds):取值范围为0-59。
- 分钟(Minutes):取值范围为0-59。
- 小时(Hours):取值范围为0-23。
- 日期(Day of month):取值范围为1-31。
- 月份(Month):取值范围为1-12或使用英文缩写(如JAN-DEC)。
- 星期(Day of week):取值范围为0-7或使用英文缩写(SUN-SAT),其中0和7都表示星期日。
cron
表达式的格式如下:"秒 分 时 日 月 周"
例如,如果要每天中午12点执行一次任务,可以使用如下的
cron
表达式:@Scheduled(cron = "0 0 12 * * ?")
在上述表达式中,
0 0 12 * * ?
表示每天中午12点执行一次任务。在实际使用中,根据具体的需求可以灵活设置cron
表达式来指定定时任务的执行时间。需要注意的是,cron
表达式中不同字段之间用空格分隔,同时还可以使用通配符、区间等方式来设置更复杂的定时规则。
在cron
表达式中,可以使用一些特殊的符号来设置更复杂的定时规则。以下是常用的通配符和区间符号:
通配符:
*
:表示匹配任意值。例如,*
在分钟字段表示每分钟都执行。?
:仅用于日和星期字段,表示不指定具体值。区间:
-
:表示范围。例如,1-5
在小时字段表示1点到5点之间每个整点触发。/
:表示步长。例如,0/5
在秒字段表示每隔5秒执行一次。列表:
,
:表示列表。可以指定多个值逗号分隔。例如,1,3,5
在小时字段表示1点、3点和5点各执行一次。通配符和区间的结合:
- 可以结合通配符和区间来设置更复杂的定时规则。例如,
0 0 0 1-10 * ?
表示在每个月的1号到10号的午夜零点触发。工作日和非工作日:
W
:表示最接近给定日期的工作日(周一至周五)。例如,15W
在日字段表示离每月15号最近的工作日触发。L
:表示最后一天。例如,L
在日字段表示每个月的最后一天触发。
三. 实现定时任务的异步执行:
为什么要实现异步执行定时任务?主要有以下优点:
提高系统性能:
- 异步执行可以避免因为同步执行而造成的阻塞,提高系统的并发能力和响应速度。通过异步执行,系统可以同时处理多个任务,充分利用系统资源,提升系统整体性能。
增强用户体验:
- 异步执行可以确保用户操作的及时响应,避免因为任务耗时长而导致用户界面假死或响应缓慢的情况发生。用户在等待任务完成的过程中可以继续进行其他操作,提升用户体验。
任务解耦和模块化:
- 通过异步执行,可以将任务之间的耦合度降低,实现任务的解耦和模块化。不同的任务可以独立执行,各自管理自己的状态和资源,提高系统的灵活性和可维护性。
提高系统稳定性:
- 异步执行可以将任务的执行隔离开来,降低任务之间的相互影响,提高系统的稳定性和容错能力。即使某个任务执行失败,也不会对系统的整体运行造成严重影响。
资源管理和调度优化:
- 通过异步执行,可以更好地管理系统资源,优化任务调度策略,提高系统的资源利用率和效率。合理安排任务的执行顺序和时间,可以更好地满足业务需求。
实现定时任务异步执行的方法有多种,这里主要介绍使用Spring Framework中的@Async注解来实现异步执行定时任务,通过在方法上添加@Async注解,Spring会在调用该方法时自动创建一个新的线程来执行该方法,从而实现异步执行。
代码示例:
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@Async
public void doSomethingAsync() {
// 异步执行的任务代码
}
}
在使用@Async注解时,需要在Spring配置类或者启动类上添加@EnableAsync注解来启用对异步方法的支持,例如:
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration
@EnableAsync
public class AppConfig {
// 配置信息
}
当使用@Async
注解时,Spring会默认使用一个线程池来执行异步方法。这个线程池是由Spring自动配置的,默认情况下,它会使用一个SimpleAsyncTaskExecutor
来执行异步方法。
我们可以在Spring的配置类中创建一个TaskExecutor
bean,并在使用@Async
注解时指定要使用的线程池。下面是一个简单的示例:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
public class AppConfig implements AsyncConfigurer {
@Override
@Bean
public TaskExecutor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.initialize();
return executor;
}
}
在上面的示例中,我们创建了一个ThreadPoolTaskExecutor
bean,并通过重写AsyncConfigurer
接口的getAsyncExecutor()
方法,返回我们自定义的线程池实例。在这个示例中,我们设置了线程池的核心线程数、最大线程数和队列容量,并将其初始化后返回给Spring容器。
接着,我们可以在需要使用异步方法的地方,使用@Async
注解并指定要使用的线程池。例如:
import org.springframework.scheduling.annotation.Async;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@Async("getAsyncExecutor")
public void doSomethingAsync() {
// 异步执行的任务代码
}
}
在上面的示例中,我们在doSomethingAsync
方法上使用了@Async("getAsyncExecutor")
注解,指定了要使用的线程池名为getAsyncExecutor
,这样就可以使用我们自定义的线程池来执行异步方法了。
那么要实现定时任务的异步执行就很简单了,例如:
@Async("threadPoolTaskExecutor")
@Scheduled(cron = "0 0/30 * * * ?")
public void GrabFileInformation() {
dataService.getAllDataTASK();
log.info("执行了抓取数据定时任务!");
}
记得在配置类上加上@EnableAsync和@EnableScheduing注解即可。