SpringBoot定时任务(附本地运行正常部署服务器定时任务多次执行解决方案)

本文探讨了SpringBoot中两种定时任务的实现方式——注解和接口实现,并分享了解决发布到服务器后定时任务重复执行的问题。问题源于Tomcat服务器的配置,特别是context节点的设置。解决方案是调整或移除不必要的映射配置,确保服务只启动一次。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringBoot定时任务

①注解方式

import cn.hutool.core.date.DateUtil;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
@EnableScheduling
public class CronTask01 {

  @Scheduled(cron = "0/5 * * * * ?")
  public void cron(){
    String date = DateUtil.format(new Date(),"HH:mm:ss");
    System.out.println(date+"注解方式执行定时任务.....");

  }
}

②接口实现方式

import cn.hutool.core.date.DateUtil;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import java.util.Date;

@Component
@EnableScheduling
public class CronTask02 implements SchedulingConfigurer {

  //引入springboot为定时任务自带的线程池对象
  @Autowired
  ThreadPoolTaskScheduler pool;
    
  @Override
  public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {   
     String cron = "0/5 * * * * ?";
      
    //设置线程池数量为1
    pool.setPoolSize(1);
    //设置定时任务线程池
    taskRegistrar.setTaskScheduler(pool);
      
      
    taskRegistrar.addCronTask(() -> {
      String s = DateUtil.format(new Date(), "HH:mm:ss");
      System.out.println(s + "接口方式执行定时任务..........");
    }, cron);
      
//    taskRegistrar.addTriggerTask(() -> {
//      String s = DateUtil.format(new Date(), "HH:mm:ss");
//      System.out.println(s+"接口方式执行定时任务..........");
//    }, triggerContext -> {
//      CronTrigger trigger = new CronTrigger(cron);
//      Date date = trigger.nextExecutionTime(triggerContext);
//      return date;
//    });
      
  }
}

PS:开发时无论用哪种方式在本地都可以运行正常,但是一旦发布到服务器Tomcat下,定时任务会在设定时间执行两遍。一开始打印日志发现有多个线程在运行,但是把线程池数量设为1之后还会执行两遍,最后发现是Tomcat服务配置文件映射问题,配置文件为“**/tomcat/conf/server.xml”。为了启动后可以访问服务器上的图片,在外部建了一个文件夹存放图片,并在server.xml文件中添加如下配置(context节点):

<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
  <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log" suffix=".txt" />
  <!-- <Context crossContext="true" docBase="/www/wwwroot/images" path="" reloadable="true" /> -->
</Host>   

docBase表示图片存放位置,猜测因为映射关系导致服务运行两次,故把context节点删除之后定时任务正常执行一遍!

如果还想访问服务器图片只需在“**/tomcat/webapps”目录即war包所在目录下新建文件夹存放图片即可。

<think>嗯,用户想了解如何在Spring Boot中每小时运行一次任务。首先,我得想到Spring Boot常用的任务调度方法。Spring框架本身提供了@Scheduled注解,这可能是一个解决方案。 那用户的需求是每小时执行一次,对吧?使用@Scheduled的话,需要配置cron表达式,或者是固定延迟、固定速率。但固定延迟和速率可能不太精确,特别是如果任务执行时间较长的话,可能会有偏差。所以cron表达式可能更合适。 接下来,我得确定正确的cron表达式。每小时运行一次的话,应该是在每小时的0分0秒执行。那对应的cron表达式应该是“0 0 * * * *”吗?记得Springcron表达式有六个字段,分别代表秒、分、时、日、月、周几。所以每小时的第一分钟第一秒执行的话,秒字段是0,分钟字段是0,其他用星号通配。 然后,用户需要在Spring Boot应用中启用调度功能,这需要加上@EnableScheduling注解在配置类或者主类上。然后在具体的方法上使用@Scheduled(cron = "0 0 * * * *")。这样方法就会每小时执行一次了。 不过,用户可能还需要考虑时区的问题。如果应用部署在不同时区的服务器上,可能需要指定时区参数,比如cron = "0 0 * * * *", zone = "Asia/Shanghai"。这样可以确保任务在预期的时区执行。 另外,还有一种方法是使用fixedRate,比如@Scheduled(fixedRate = 3600000),单位是毫秒,这样每隔一小时执行一次。但这种方法的问题在于,如果任务执行时间超过了一小时,可能会同时有多个任务实例运行,需要注意线程池的配置和任务的并发处理。 还需要提醒用户,确保添加了@EnableScheduling,否则定时任务不会生效。同时,检查依赖是否正确,Spring Bootspring-boot-starter-web或者spring-boot-starter已经包含了必要的调度依赖,但如果有问题可能需要显式添加spring-context-support。 可能的错误点:用户可能误用了cron表达式,比如少了一个字段,或者分和时的位置搞错了。比如写成“0 * * * *”就会每分钟执行一次,而不是每小时。另外,时区设置也可能被忽略,导致任务执行时间不符合预期。 总结下来,步骤应该是:1. 启用调度;2. 编写任务方法并使用正确的cron表达式;3. 考虑时区配置;4. 处理可能的并发问题。然后给出示例代码,确保用户能正确实现。</think>在 Spring Boot 中实现每小时运行一次的任务,可通过以下步骤完成: --- ### 1. **启用定时任务功能** 在 Spring Boot 主类或配置类上添加 `@EnableScheduling` 注解: ```java @SpringBootApplication @EnableScheduling // 关键注解 public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } } ``` --- ### 2. **编写定时任务方法** 使用 `@Scheduled` 注解定义任务执行频率。每小时运行一次有以下两种实现方式: #### **方式 1:Cron 表达式** ```java @Component public class MyScheduledTask { // 每小时的第 0 分 0 秒执行(例如 13:00:00, 14:00:00) @Scheduled(cron = "0 0 * * * *") public void hourlyTask() { // 任务逻辑,例如清理缓存、发送报告等 System.out.println("任务执行时间:" + new Date()); } } ``` #### **方式 2:固定间隔时间** ```java @Scheduled(fixedRate = 3600000) // 单位毫秒(1小时=3600000ms) public void hourlyTask() { // 任务逻辑 } ``` --- ### 3. **Cron 表达式详解** - `0 0 * * * *` 表示: $$秒(0)\quad 分钟(0)\quad 小时(任意)\quad 日期(任意)\quad 月份(任意)\quad 星期(任意)$$ 即每小时的第 0 分 0 秒触发。 --- ### 4. **时区配置(可选)** 若需指定时区,可添加 `zone` 参数: ```java @Scheduled(cron = "0 0 * * * *", zone = "Asia/Shanghai") public void hourlyTask() { /* ... */ } ``` --- ### 5. **注意事项** - **依赖检查**:确保项目中包含 `spring-boot-starter-web` 或 `spring-boot-starter`,它们已集成定时任务依赖。 - **单线程问题**:默认使用单线程执行任务,若任务耗时较长,需通过 `@Async` + 线程池配置实现并发。 - **分布式环境**:在集群部署时,需结合分布式锁(如 Redis 锁)避免重复执行。 --- ### 示例完整代码 ```java @Component public class MyScheduledTask { @Scheduled(cron = "0 0 * * * *") public void hourlyTask() { // 实际业务逻辑 System.out.println("每小时任务已执行,时间:" + LocalDateTime.now()); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值