SpringBoot定时任务(三十三)

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

二八佳人体似酥腰间仗剑斩愚夫。虽然不见人头落暗里教君骨髓枯。

上一章简单介绍了SpringBoot系统启动任务(三十二)的方式,如果没有看过,请观看上一章

定时任务主要使用的是 @Scheduled 注解

关于 Cron 表达式 可以看老蝴蝶之前的文章:

https://blog.csdn.net/yjltx1234csdn/article/details/105846493

SpringBoot 使用 @Scheduled 定时任务

pom.xml 依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

application.yml 配置

server:
  port: 8081
  servlet:
    context-path: /Job

添加 @EnableScheduling 注解

@SpringBootApplication
//开启定时任务的注解
@EnableScheduling
@Log4j2
public class JobApplication {
    public static void main(String[] args) {
        SpringApplication.run(JobApplication.class,args);
        log.info("运行定时任务启动成功");
    }
}

定时任务配置类

@Component
@Log4j2
public class MyJob {
    
}

fixedRate 和 fixedDelay 属性

fixedRate 表示任务执行之间的时间间隔具体是指两次任务的开始时间间隔。 但可能存在第二次任务开始时第一次任务还没有结束的可能。

fixedDelay 表示任务执行之间的时间间隔 具体是指本次任务结束到下次任务开始之间的时间间隔。

单位都是毫秒

fixedRate

    //每2秒执行一次是上一次启动和这一次启动的时间间隔
    @Scheduled(fixedRate = 2000)
    public void job1(){
        sayHello();
    }

	public void sayHello(){
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        String now=simpleDateFormat.format(new Date());
        System.out.println(">>>你好当前时间是:"+now);
    }

启动程序:

>>>你好当前时间是:2023-01-03 17:12:17.389
2023-01-03 17:12:17.398  INFO 13768 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path '/Job'
2023-01-03 17:12:17.400  INFO 13768 --- [  restartedMain] top.yueshushu.learn.JobApplication       : Started JobApplication in 2.163 seconds (JVM running for 2.645)
2023-01-03 17:12:17.400  INFO 13768 --- [  restartedMain] top.yueshushu.learn.JobApplication       : 运行定时任务启动成功
>>>你好当前时间是:2023-01-03 17:12:19.390
>>>你好当前时间是:2023-01-03 17:12:21.390
>>>你好当前时间是:2023-01-03 17:12:23.391

大概每隔两秒执行一次

fixedDelay

   //每2秒执行一次是上一次结束和这一次启动的时间间隔
    @Scheduled(fixedDelay = 2000)
    public void job2(){
        sayHello();
    }

启动程序: 后面的毫秒数是依次递增的 因为 执行 sayHello() 方法 也需要一个时间.

>>>你好当前时间是:2023-01-03 17:16:00.148
2023-01-03 17:16:00.157  INFO 33904 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path '/Job'
2023-01-03 17:16:00.158  INFO 33904 --- [  restartedMain] top.yueshushu.learn.JobApplication       : Started JobApplication in 1.685 seconds (JVM running for 2.205)
2023-01-03 17:16:00.159  INFO 33904 --- [  restartedMain] top.yueshushu.learn.JobApplication       : 运行定时任务启动成功
>>>你好当前时间是:2023-01-03 17:16:02.149
>>>你好当前时间是:2023-01-03 17:16:04.151
>>>你好当前时间是:2023-01-03 17:16:06.152
>>>你好当前时间是:2023-01-03 17:16:08.154
>>>你好当前时间是:2023-01-03 17:16:10.156
>>>你好当前时间是:2023-01-03 17:16:12.157
>>>你好当前时间是:2023-01-03 17:16:14.158
>>>你好当前时间是:2023-01-03 17:16:16.159
>>>你好当前时间是:2023-01-03 17:16:18.161

添加睡眠程序使方法执行时间变长 这个效果就很明显了。

执行程序时间过长 fixedRate 和 fixedDelay 区别

休眠 3s, 超过了任务执行的频率

    @Scheduled(fixedRate = 2000)
    public void job3() throws Exception{
        log.info(">>>>fixedRate 进来了");
        Thread.sleep(3000);
    }

    @Scheduled(fixedDelay = 2000)
    public void job31() throws Exception{
        log.info(">>>>fixedDelay 进来了");
        //休眠 3000s
        Thread.sleep(3000);
    }

fixedRate:

2023-01-03 17:19:57.320  INFO 4624 --- [   scheduling-1] top.yueshushu.learn.jobConfig.MyJob      : >>>>fixedRate 进来了
2023-01-03 17:20:00.321  INFO 4624 --- [   scheduling-1] top.yueshushu.learn.jobConfig.MyJob      : >>>>fixedRate 进来了
2023-01-03 17:20:03.322  INFO 4624 --- [   scheduling-1] top.yueshushu.learn.jobConfig.MyJob      : >>>>fixedRate 进来了
2023-01-03 17:20:04.255  INFO 4624 --- [_ClusterManager] o.s.s.quartz.LocalDataSourceJobStore     : ClusterManager: detected 1 failed or restarted instances.
2023-01-03 17:20:04.255  INFO 4624 --- [_ClusterManager] o.s.s.quartz.LocalDataSourceJobStore     : ClusterManager: Scanning for instance "Yuejl1672737568619"'s failed in-progress jobs.
2023-01-03 17:20:04.338  INFO 4624 --- [_ClusterManager] o.s.s.quartz.LocalDataSourceJobStore     : ClusterManager: ......Freed 1 acquired trigger(s).
2023-01-03 17:20:06.323  INFO 4624 --- [   scheduling-1] top.yueshushu.learn.jobConfig.MyJob      : >>>>fixedRate 进来了
2023-01-03 17:20:09.323  INFO 4624 --- [   scheduling-1] top.yueshushu.learn.jobConfig.MyJob      : >>>>fixedRate 进来了
2023-01-03 17:20:12.324  INFO 4624 --- [   scheduling-1] top.yueshushu.learn.jobConfig.MyJob      : >>>>fixedRate 进来了

每隔 3s 执行一次。

fixedDelay:

2023-01-03 17:22:47.771  INFO 29908 --- [   scheduling-1] top.yueshushu.learn.jobConfig.MyJob      : >>>>fixedDelay 进来了
2023-01-03 17:22:47.780  INFO 29908 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path '/Job'
2023-01-03 17:22:47.782  INFO 29908 --- [  restartedMain] top.yueshushu.learn.JobApplication       : Started JobApplication in 1.545 seconds (JVM running for 2.032)
2023-01-03 17:22:47.782  INFO 29908 --- [  restartedMain] top.yueshushu.learn.JobApplication       : 运行定时任务启动成功
2023-01-03 17:22:47.794  INFO 29908 --- [_MisfireHandler] o.s.s.quartz.LocalDataSourceJobStore     : Handling 1 trigger(s) that missed their scheduled fire-time.
2023-01-03 17:22:52.773  INFO 29908 --- [   scheduling-1] top.yueshushu.learn.jobConfig.MyJob      : >>>>fixedDelay 进来了
2023-01-03 17:22:57.774  INFO 29908 --- [   scheduling-1] top.yueshushu.learn.jobConfig.MyJob      : >>>>fixedDelay 进来了
2023-01-03 17:23:02.776  INFO 29908 --- [   scheduling-1] top.yueshushu.learn.jobConfig.MyJob      : >>>>fixedDelay 进来了
2023-01-03 17:23:07.782  INFO 29908 --- [   scheduling-1] top.yueshushu.learn.jobConfig.MyJob      : >>>>fixedDelay 进来了

发现 每隔 5s (2s+3s) 执行一次。

使用 fixedDelay 执行的时间与任务方法执行的花费时间有关 可能时间并不是真实要使用的时间。

建议 使用 fixedRate 来表示频率。

initialDelay 首次任务启动的延迟时间

    //initialDelay 首次任务启动的延迟时间
   @Scheduled(initialDelay = 3000,fixedRate = 2000)
    public void job4() throws Exception{
        sayHello();
    }

程序启动成功 3s后 再执行定时任务, 再以2s 的频率执行

2023-01-03 17:27:07.556  INFO 2996 --- [  restartedMain] top.yueshushu.learn.JobApplication       : 运行定时任务启动成功
2023-01-03 17:27:07.640  INFO 2996 --- [_MisfireHandler] o.s.s.quartz.LocalDataSourceJobStore     : Handling 1 trigger(s) that missed their scheduled fire-time.
>>>你好当前时间是:2023-01-03 17:27:10.546
>>>你好当前时间是:2023-01-03 17:27:12.547
>>>你好当前时间是:2023-01-03 17:27:14.545

Cron 表达式

cron 表达式: 3/2 * * * * *

	// cron 表达式
    @Scheduled(cron = "3/2 * * * * *")
    public void job5() throws Exception{
        sayHello();
    }
2023-01-03 17:29:02.002  INFO 7296 --- [           main] top.yueshushu.learn.JobApplication       : 运行定时任务启动成功
2023-01-03 17:29:02.069  INFO 7296 --- [_MisfireHandler] o.s.s.quartz.LocalDataSourceJobStore     : Handling 1 trigger(s) that missed their scheduled fire-time.
>>>你好当前时间是:2023-01-03 17:29:03.002
>>>你好当前时间是:2023-01-03 17:29:05.001
>>>你好当前时间是:2023-01-03 17:29:07.014

Cron 业务调用

定义一个 业务操作 UserService.addUser

@Service
@Log4j2
public class UserServiceImpl implements UserService {

    @Override
    public void addUser(User user) {
        log.info("执行添加员工的操作");
    }
}
    //里面使用 userService 实例
    @Resource
    private UserService userService;
    @Scheduled(cron = "3/2 * * * * *")
    public void job6() throws Exception{
        //执行任务复杂的情况不建议使用.
        // 采用 quartz 的方式实现
        userService.addUser(null);
    }
2023-01-03 17:32:48.882  INFO 7816 --- [           main] top.yueshushu.learn.JobApplication       : 运行定时任务启动成功
2023-01-03 17:32:48.883  INFO 7816 --- [_MisfireHandler] o.s.s.quartz.LocalDataSourceJobStore     : Handling 1 trigger(s) that missed their scheduled fire-time.
2023-01-03 17:32:49.002  INFO 7816 --- [   scheduling-1] t.y.learn.service.UserServiceImpl        : 执行添加员工的操作
2023-01-03 17:32:51.001  INFO 7816 --- [   scheduling-1] t.y.learn.service.UserServiceImpl        : 执行添加员工的操作
2023-01-03 17:32:53.002  INFO 7816 --- [   scheduling-1] t.y.learn.service.UserServiceImpl        : 执行添加员工的操作
2023-01-03 17:32:55.001  INFO 7816 --- [   scheduling-1] t.y.learn.service.UserServiceImpl        : 执行添加员工的操作

业务调用也是可以的。

异步方法调用

当执行任务方法花费时间过长时 异步处理

    @Override
    public void addUser(User user) {
        try{
            TimeUnit.SECONDS.sleep(3);
        }catch (Exception e){

        }
        log.info("执行添加员工的操作");
    }

不异步之前

变成了 每隔 4s 执行一次了。

2023-01-03 17:35:35.681  INFO 11884 --- [           main] top.yueshushu.learn.JobApplication       : 运行定时任务启动成功
2023-01-03 17:35:35.699  INFO 11884 --- [_MisfireHandler] o.s.s.quartz.LocalDataSourceJobStore     : Handling 1 trigger(s) that missed their scheduled fire-time.
2023-01-03 17:35:40.001  INFO 11884 --- [   scheduling-1] t.y.learn.service.UserServiceImpl        : 执行添加员工的操作
2023-01-03 17:35:44.003  INFO 11884 --- [   scheduling-1] t.y.learn.service.UserServiceImpl        : 执行添加员工的操作
2023-01-03 17:35:48.002  INFO 11884 --- [   scheduling-1] t.y.learn.service.UserServiceImpl        : 执行添加员工的操作
2023-01-03 17:35:52.008  INFO 11884 --- [   scheduling-1] t.y.learn.service.UserServiceImpl        : 执行添加员工的操作
2023-01-03 17:35:56.002  INFO 11884 --- [   scheduling-1] t.y.learn.service.UserServiceImpl        : 执行添加员工的操作

异步

添加 @EnableAsync 注解

@SpringBootApplication
//开启定时任务的注解
@EnableScheduling
@EnableAsync
@Log4j2
public class JobApplication {
    public static void main(String[] args) {
        SpringApplication.run(JobApplication.class,args);
        log.info("运行定时任务启动成功");
    }
}

任务方法上添加 @Async 注解

 	@Override
    @Async
    public void addUser(User user) {
        try{
            TimeUnit.SECONDS.sleep(3);
        }catch (Exception e){

        }
        log.info("执行添加员工的操作");
    }

执行, 每隔 2s 执行一次。

2023-01-03 17:38:48.338  INFO 8916 --- [           main] top.yueshushu.learn.JobApplication       : 运行定时任务启动成功
2023-01-03 17:38:48.416  INFO 8916 --- [_MisfireHandler] o.s.s.quartz.LocalDataSourceJobStore     : Handling 1 trigger(s) that missed their scheduled fire-time.
2023-01-03 17:38:52.022  INFO 8916 --- [         task-1] t.y.learn.service.UserServiceImpl        : 执行添加员工的操作
2023-01-03 17:38:54.002  INFO 8916 --- [         task-2] t.y.learn.service.UserServiceImpl        : 执行添加员工的操作
2023-01-03 17:38:56.003  INFO 8916 --- [         task-3] t.y.learn.service.UserServiceImpl        : 执行添加员工的操作
2023-01-03 17:38:58.003  INFO 8916 --- [         task-4] t.y.learn.service.UserServiceImpl        : 执行添加员工的操作

动态 Cron 配置

目前的 cron

@Component
@Log4j2
public class MyDynamicCronJob implements SchedulingConfigurer {
    public static String helloCron = "3/2 * * * * *";
    public void sayHello(){
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        String now=simpleDateFormat.format(new Date());
        System.out.println(">>>你好当前时间是:"+now);
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(
                () -> {
                    // 调用方法
                    sayHello();
                },
                new Trigger() {
                    @Override
                    public Date nextExecutionTime(TriggerContext triggerContext) {
                        // 配置下一次执行时间
                        CronTrigger cronTrigger = new CronTrigger(helloCron);
                        return cronTrigger.nextExecutionTime(triggerContext);
                    }
                }
        );
    }
}

方法动态改变 cron 的值

@RestController
public class CronController {

    @RequestMapping("/setCron")
    public String setCron() {
        int maxRate = new Random().nextInt(10) +4;
        String cron = "3/"+maxRate+" * * * * *";
        MyDynamicCronJob.helloCron = cron;
        return cron;
    }
}

访问地址: http://localhost:8081/Job/setCron 改成了 7

>>>你好当前时间是:2023-01-03 18:56:19.001
2023-01-03 18:56:19.047  INFO 3360 --- [_MisfireHandler] o.s.s.quartz.LocalDataSourceJobStore     : Handling 1 trigger(s) that missed their scheduled fire-time.
>>>你好当前时间是:2023-01-03 18:56:21.002
>>>你好当前时间是:2023-01-03 18:56:23.007
>>>你好当前时间是:2023-01-03 18:56:25.016
>>>你好当前时间是:2023-01-03 18:56:27.009
>>>你好当前时间是:2023-01-03 18:56:29.016
2023-01-03 18:56:30.201  INFO 3360 --- [nio-8081-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/Job]    : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-01-03 18:56:30.201  INFO 3360 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-01-03 18:56:30.206  INFO 3360 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 5 ms
>>>你好当前时间是:2023-01-03 18:56:31.005
>>>你好当前时间是:2023-01-03 18:56:38.001
>>>你好当前时间是:2023-01-03 18:56:45.002

动态 Cron 配置成功

本章节的代码放置在 github 上:

https://github.com/yuejianli/springboot/tree/develop/SpringBoot_Job

谢谢您的观看如果喜欢请关注我再次感谢 !!!

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Spring