百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文
SpringBoot示例,第5期:3种方式实现定时任务

SpringBoot示例,第5期:3种方式实现定时任务

  • 网站名称:SpringBoot示例,第5期:3种方式实现定时任务
  • 网站分类:技术文章
  • 收录时间:2025-09-04 00:25
  • 网站地址:

进入网站

“SpringBoot示例,第5期:3种方式实现定时任务” 网站介绍

1、基于@Scheduled注解

定时任务类:

package com.xy.schedule;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
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;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
@Component
@EnableScheduling
public class ScheduleTask {
    //    @Scheduled(fixedRate = 5000) // 每隔5秒执行一次  
    @Scheduled(cron = "0/5 * * * * *") // 每隔5秒执行一次  
    public void taskA() throws InterruptedException {
        LocalDateTime now = LocalDateTime.now();
        // 定义时间格式,不包含毫秒  
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 格式化并打印时间  
        String formattedTime = now.format(formatter);
        System.out.println("taskA当前时间: " + formattedTime);
        TimeUnit.SECONDS.sleep(10);
        System.out.println("taskA当前时间 end");
    }
    //    @Scheduled(fixedRate = 5000) // 每隔5秒执行一次  
    @Scheduled(cron = "0/5 * * * * *") // 每隔5秒执行一次  
    public void taskB() {
        LocalDateTime now = LocalDateTime.now();
        // 定义时间格式,不包含毫秒  
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 格式化并打印时间  
        String formattedTime = now.format(formatter);
        System.out.println("taskB当前时间: " + formattedTime);
    }
}

这种写法有个缺点,就是几个定时任务在同一个线程呢,任务互相干扰。

也就是说会等其中一个任务执行完了,才会去执行下一个。

修改成:

package com.xy.schedule;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
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;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
@Component
@EnableScheduling
@EnableAsync
public class ScheduleTask {
    //    @Scheduled(fixedRate = 5000) // 每隔5秒执行一次  
    @Scheduled(cron = "0/5 * * * * *") // 每隔5秒执行一次  
    @Async
    public void taskA() throws InterruptedException {
        LocalDateTime now = LocalDateTime.now();
        // 定义时间格式,不包含毫秒  
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 格式化并打印时间  
        String formattedTime = now.format(formatter);
        System.out.println("taskA当前时间: " + formattedTime);
        TimeUnit.SECONDS.sleep(10);
        System.out.println("taskA当前时间 end");
    }
    //    @Scheduled(fixedRate = 5000) // 每隔5秒执行一次  
    @Scheduled(cron = "0/5 * * * * *") // 每隔5秒执行一次  
    @Async
    public void taskB() {
        LocalDateTime now = LocalDateTime.now();
        // 定义时间格式,不包含毫秒  
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 格式化并打印时间  
        String formattedTime = now.format(formatter);
        System.out.println("taskB当前时间: " + formattedTime);
    }
}

基于注解有个不足的地方,无法动态修改cron表达式,只能写死在注解上。

2、基于接口

基于SchedulingConfigurer接口:

package com.xy.schedule;
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 {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(
                //添加任务内容
                () -> process(),
                //设置执行的周期
                triggerContext -> {
                    //查询cron表达式
                    String cron = "0/5 * * * * *";//这个就可以通过查数据库获取
                    if (cron.isEmpty()) {
                        System.out.println("cron is null");
                    }
                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                });
    }
    private void process() {
        System.out.println("基于接口的定时任务");
    }
}

这种写法就是比较麻烦,每个任务都要新建一个类实现接口。

3、使用Quartz

使用Quartz:首先定义JobDetail(任务详情),然后再定义触发器,就是定义cron表达式。

package com.xy.config;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QuartzConfig {
    @Bean("helloJob")
    public JobDetail helloJobDetail() {
        return JobBuilder.newJob(HelloJob.class)
                .withIdentity("helloJob")
                .usingJobData("msg", "Hello Quartz")
                .storeDurably()//即使没有Trigger关联时,也不需要删除该JobDetail
                .build();
    }
    @Bean
    public Trigger helloJobTrigger() {
        // 每秒执行一次
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
        return TriggerBuilder.newTrigger()
                .forJob(helloJobDetail())
                .withIdentity("helloJobTrigger")
                .withSchedule(cronScheduleBuilder)
                .build();
    }
}

新建任务:

package com.xy.config;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.util.Date;
@Slf4j
public class HelloJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        // get parameters
        context.getJobDetail().getJobDataMap().forEach(
                (k, v) -> log.info("param, key:{}, value:{}", k, v)
        );
        // your logics
        log.info("Hello Job执行时间: " + new Date());
    }
}

一个简单的Quartz就完成了,还是比较推荐用Quartz吧