SpringBoot中实现定时任务的几种方式
一、基于注解
这种方式很简单,主要就是先@EnableScheduling
开启定时任务功能,然后在相应的方法上添加@Scheduled()
中间写上相应的cron
表达式即可。示例如下:
schedule.ScheduleTask:
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.time.LocalDateTime; @Component @EnableScheduling //开启定时任务 public class ScheduleTask { @Scheduled(cron = "0/5 * * * * ?") //定时任务注解+cron表达式 public void testScheduleTask() { System.out.println("执行定时任务" + LocalDateTime.now()); } }
Cron表达式参数参考:
- 秒(0~59) 例如0/5表示每5秒
- 分(0~59)
- 时(0~23)
- 日(0~31)的某天,需计算
- 月(0~11)
- 周几( 可填1-7 或 SUN/MON/TUE/WED/THU/FRI/SAT)
建议:直接在线生成Cron表达式比较方便:www.matools.com/cron/
@Scheduled
:除了支持灵活的参数表达式cron
之外,还支持 fixedDelay
,fixedRate
,initialDelay
这些延时性的操作。
启动测试就实现了基本的定时任务功能,但是如果我们修改了cron
表达式,需要重启整个应用才能生效,不是很方便。想要实现修改cron
表达式就生效就需要用到接口
的方式来实现定时任务。
二、基于接口
接口的方式是我们把定时任务的信息放在数据库中,程序从数据库去拉取定时任务的信息如cron
表达式来实现实时修改生效等功能。
1. 首先在数据库中创建一张用来记录定时任务的表
CREATE TABLE `scheduled` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(255) NULL, `cron` varchar(255) NULL, PRIMARY KEY (`id`) ) INSERT INTO `mydb`.`scheduled` (`id`, `name`, `cron`) VALUES (1, '定时任务1', '0/6 * * * * ?')
2. 在项目中引入mabatis-plus
和mysql
相应的依赖包
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.32</version> </dependency>
3. 在application.yml
中进行连接数据库相应配置
spring: datasource: url: jdbc:mysql://localhost:3306/mydb?characterEncoding=utf-8&serverTimeZone=UTC username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver
4. 定义查询cron
表达式的mapper
mapper.CronMapper:
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; @Mapper public interface CronMapper { @Select("select cron from scheduled where id=#{id}") String getCron(Long id); }
5. 实现定时任务
import com.jk.mapper.CronMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.SchedulingConfigurer; import org.springframework.scheduling.config.ScheduledTaskRegistrar; import org.springframework.scheduling.support.CronTrigger; import org.springframework.stereotype.Component; @Component @EnableScheduling //开启定时任务 public class ScheduleTask implements SchedulingConfigurer { @Autowired private CronMapper cronMapper; @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.addTriggerTask( //添加任务内容 () -> process(), //设置执行的周期 triggerContext -> { //查询cron表达式 String cron = cronMapper.getCron(1L); if (cron.isEmpty()) { System.out.println("cron is null"); } return new CronTrigger(cron).nextExecutionTime(triggerContext); }); } private void process() { System.out.println("基于接口的定时任务"); } }
这种方式需要去实现SchedulingConfigurer
接口并重写configureTasks
方法,然后设置任务内容和执行周期等,启动测试就实现了基于接口的定时任务,此时我们改动数据库里的cron
表达式也会实时生效
三、多线程定时任务
但上面的方法定义的定时任务会有个问题,就是如果我一个定时任务里面执行了复杂逻辑,导致本身执行花的时间就已经超过了定时任务间隔的时间怎么办呢?这时候定时任务的执行就会出现一定的问题,具体如下,我用线程睡眠的方式模拟处理复杂逻辑
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.time.LocalDateTime; @Component @EnableScheduling //开启定时任务 public class ScheduleTask { @Scheduled(cron = "0/5 * * * * ?") //定时任务注解+cron表达式 public void testScheduleTask1() throws InterruptedException { System.out.println("执行定时任务1 " + LocalDateTime.now()); Thread.sleep(10 * 1000); } @Scheduled(cron = "0/5 * * * * ?") //定时任务注解+cron表达式 public void testScheduleTask2() { System.out.println("执行定时任务2 " + LocalDateTime.now()); } }
可以看到两个任务的执行时间都被影响了,和我们设置的5秒不对应。此时就可以使用多线程定时任务
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.time.LocalDateTime; @Component @EnableScheduling //开启定时任务 @EnableAsync //开启多线程 public class ScheduleTask { @Scheduled(cron = "0/5 * * * * ?") //定时任务注解+cron表达式 @Async public void testScheduleTask1() throws InterruptedException { System.out.println("执行定时任务1 " + LocalDateTime.now()); Thread.sleep(10 * 1000); } @Scheduled(cron = "0/5 * * * * ?") //定时任务注解+cron表达式 @Async public void testScheduleTask2() { System.out.println("执行定时任务2 " + LocalDateTime.now()); } }
这样多线程的定时任务就实现了,每个定时任务之间不会互相影响,定时任务执行时间太长也不会影响。
这就是定时任务实现的几种方式,对大家有帮助的话多多
点赞
、收藏
哦,感谢!
以上就是SpringBoot中实现定时任务的几种方式的详细内容,更多关于SpringBoot 定时任务的资料请关注脚本之家其它相关文章!
相关文章
java 中HashMap、HashSet、TreeMap、TreeSet判断元素相同的几种方法比较
这篇文章主要介绍了从源码的角度浅析HashMap、TreeMap元素的存储和获取元素的逻辑;从Map与Set之间的关系浅析常用的Set中元素的存储和判断是否重复的逻辑,需要的朋友可以参考下2017-01-01IntelliJ IDEA设置代码的快捷编辑模板Live Templates
今天小编就为大家分享一篇关于IntelliJ IDEA设置代码的快捷编辑模板Live Templates,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧2018-10-10SpringBoot ApplicationContextAware拓展接口使用详解
当一个类实现了这个接口(ApplicationContextAware)之后,这个类就可以方便获得ApplicationContext中的所有bean。换句话说,就是这个类可以直接获取spring配置文件中,所有有引用到的bean对象2023-04-04
最新评论